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 <pulse/gccmacro.h>
57 #include <pulsecore/llist.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__");
306 pthread_mutex_unlock(&func_mutex
);
314 static int dsp_cloak_enable(void) {
315 if (padsp_disabled() & 1)
318 if (getenv("PADSP_NO_DSP") || getenv("PULSE_INTERNAL"))
324 static int sndstat_cloak_enable(void) {
325 if (padsp_disabled() & 2)
328 if (getenv("PADSP_NO_SNDSTAT") || getenv("PULSE_INTERNAL"))
334 static int mixer_cloak_enable(void) {
335 if (padsp_disabled() & 4)
338 if (getenv("PADSP_NO_MIXER") || getenv("PULSE_INTERNAL"))
343 static pthread_key_t recursion_key
;
345 static void recursion_key_alloc(void) {
346 pthread_key_create(&recursion_key
, NULL
);
349 static int function_enter(void) {
350 /* Avoid recursive calls */
351 static pthread_once_t recursion_key_once
= PTHREAD_ONCE_INIT
;
352 pthread_once(&recursion_key_once
, recursion_key_alloc
);
354 if (pthread_getspecific(recursion_key
))
357 pthread_setspecific(recursion_key
, (void*) 1);
361 static void function_exit(void) {
362 pthread_setspecific(recursion_key
, NULL
);
365 static void fd_info_free(fd_info
*i
) {
368 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": freeing fd info (fd=%i)\n", i
->app_fd
);
373 pa_threaded_mainloop_stop(i
->mainloop
);
375 if (i
->play_stream
) {
376 pa_stream_disconnect(i
->play_stream
);
377 pa_stream_unref(i
->play_stream
);
381 pa_stream_disconnect(i
->rec_stream
);
382 pa_stream_unref(i
->rec_stream
);
386 pa_context_disconnect(i
->context
);
387 pa_context_unref(i
->context
);
391 pa_threaded_mainloop_free(i
->mainloop
);
393 if (i
->app_fd
>= 0) {
398 if (i
->thread_fd
>= 0) {
400 _close(i
->thread_fd
);
405 pthread_mutex_destroy(&i
->mutex
);
409 static fd_info
*fd_info_ref(fd_info
*i
) {
412 pthread_mutex_lock(&i
->mutex
);
416 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": ref++, now %i\n", i
->ref
);
417 pthread_mutex_unlock(&i
->mutex
);
422 static void fd_info_unref(fd_info
*i
) {
424 pthread_mutex_lock(&i
->mutex
);
427 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": ref--, now %i\n", i
->ref
);
428 pthread_mutex_unlock(&i
->mutex
);
434 static void context_state_cb(pa_context
*c
, void *userdata
) {
435 fd_info
*i
= userdata
;
438 switch (pa_context_get_state(c
)) {
439 case PA_CONTEXT_READY
:
440 case PA_CONTEXT_TERMINATED
:
441 case PA_CONTEXT_FAILED
:
442 pa_threaded_mainloop_signal(i
->mainloop
, 0);
445 case PA_CONTEXT_UNCONNECTED
:
446 case PA_CONTEXT_CONNECTING
:
447 case PA_CONTEXT_AUTHORIZING
:
448 case PA_CONTEXT_SETTING_NAME
:
453 static void reset_params(fd_info
*i
) {
456 i
->sample_spec
.format
= PA_SAMPLE_U8
;
457 i
->sample_spec
.channels
= 1;
458 i
->sample_spec
.rate
= 8000;
459 i
->fragment_size
= 0;
463 static const char *client_name(char *buf
, size_t n
) {
467 if ((e
= getenv("PADSP_CLIENT_NAME")))
470 if (pa_get_binary_name(p
, sizeof(p
)))
471 snprintf(buf
, n
, "OSS Emulation[%s]", p
);
473 snprintf(buf
, n
, "OSS");
478 static const char *stream_name(void) {
481 if ((e
= getenv("PADSP_STREAM_NAME")))
484 return "Audio Stream";
487 static void atfork_prepare(void) {
490 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_prepare() enter\n");
494 pthread_mutex_lock(&fd_infos_mutex
);
496 for (i
= fd_infos
; i
; i
= i
->next
) {
497 pthread_mutex_lock(&i
->mutex
);
498 pa_threaded_mainloop_lock(i
->mainloop
);
501 pthread_mutex_lock(&func_mutex
);
504 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_prepare() exit\n");
507 static void atfork_parent(void) {
510 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_parent() enter\n");
512 pthread_mutex_unlock(&func_mutex
);
514 for (i
= fd_infos
; i
; i
= i
->next
) {
515 pa_threaded_mainloop_unlock(i
->mainloop
);
516 pthread_mutex_unlock(&i
->mutex
);
519 pthread_mutex_unlock(&fd_infos_mutex
);
523 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_parent() exit\n");
526 static void atfork_child(void) {
529 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_child() enter\n");
531 /* We do only the bare minimum to get all fds closed */
532 pthread_mutex_init(&func_mutex
, NULL
);
533 pthread_mutex_init(&fd_infos_mutex
, NULL
);
535 for (i
= fd_infos
; i
; i
= i
->next
) {
536 pthread_mutex_init(&i
->mutex
, NULL
);
539 pa_context_disconnect(i
->context
);
540 pa_context_unref(i
->context
);
544 if (i
->play_stream
) {
545 pa_stream_unref(i
->play_stream
);
546 i
->play_stream
= NULL
;
550 pa_stream_unref(i
->rec_stream
);
551 i
->rec_stream
= NULL
;
554 if (i
->app_fd
>= 0) {
559 if (i
->thread_fd
>= 0) {
569 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_child() exit\n");
572 static void install_atfork(void) {
573 pthread_atfork(atfork_prepare
, atfork_parent
, atfork_child
);
576 static void stream_success_cb(pa_stream
*s
, int success
, void *userdata
) {
577 fd_info
*i
= userdata
;
582 i
->operation_success
= success
;
583 pa_threaded_mainloop_signal(i
->mainloop
, 0);
586 static void context_success_cb(pa_context
*c
, int success
, void *userdata
) {
587 fd_info
*i
= userdata
;
592 i
->operation_success
= success
;
593 pa_threaded_mainloop_signal(i
->mainloop
, 0);
596 static fd_info
* fd_info_new(fd_info_type_t type
, int *_errno
) {
598 int sfds
[2] = { -1, -1 };
600 static pthread_once_t install_atfork_once
= PTHREAD_ONCE_INIT
;
602 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": fd_info_new()\n");
604 signal(SIGPIPE
, SIG_IGN
); /* Yes, ugly as hell */
606 pthread_once(&install_atfork_once
, install_atfork
);
608 if (!(i
= malloc(sizeof(fd_info
)))) {
613 i
->app_fd
= i
->thread_fd
= -1;
618 i
->play_stream
= NULL
;
619 i
->rec_stream
= NULL
;
624 pthread_mutex_init(&i
->mutex
, NULL
);
629 pa_cvolume_reset(&i
->sink_volume
, 2);
630 pa_cvolume_reset(&i
->source_volume
, 2);
631 i
->volume_modify_count
= 0;
632 i
->sink_index
= (uint32_t) -1;
633 i
->source_index
= (uint32_t) -1;
634 i
->optr_n_blocks
= 0;
635 PA_LLIST_INIT(fd_info
, i
);
639 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, sfds
) < 0) {
641 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": socket() failed: %s\n", strerror(errno
));
646 i
->thread_fd
= sfds
[1];
648 if (!(i
->mainloop
= pa_threaded_mainloop_new())) {
650 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_threaded_mainloop_new() failed\n");
654 if (!(i
->context
= pa_context_new(pa_threaded_mainloop_get_api(i
->mainloop
), client_name(name
, sizeof(name
))))) {
656 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_context_new() failed\n");
660 pa_context_set_state_callback(i
->context
, context_state_cb
, i
);
662 if (pa_context_connect(i
->context
, NULL
, 0, NULL
) < 0) {
663 *_errno
= ECONNREFUSED
;
664 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
668 pa_threaded_mainloop_lock(i
->mainloop
);
670 if (pa_threaded_mainloop_start(i
->mainloop
) < 0) {
672 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_threaded_mainloop_start() failed\n");
673 goto unlock_and_fail
;
676 /* Wait until the context is ready */
677 pa_threaded_mainloop_wait(i
->mainloop
);
679 if (pa_context_get_state(i
->context
) != PA_CONTEXT_READY
) {
680 *_errno
= ECONNREFUSED
;
681 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
682 goto unlock_and_fail
;
685 pa_threaded_mainloop_unlock(i
->mainloop
);
690 pa_threaded_mainloop_unlock(i
->mainloop
);
700 static void fd_info_add_to_list(fd_info
*i
) {
703 pthread_mutex_lock(&fd_infos_mutex
);
704 PA_LLIST_PREPEND(fd_info
, fd_infos
, i
);
705 pthread_mutex_unlock(&fd_infos_mutex
);
710 static void fd_info_remove_from_list(fd_info
*i
) {
713 pthread_mutex_lock(&fd_infos_mutex
);
714 PA_LLIST_REMOVE(fd_info
, fd_infos
, i
);
715 pthread_mutex_unlock(&fd_infos_mutex
);
720 static fd_info
* fd_info_find(int fd
) {
723 pthread_mutex_lock(&fd_infos_mutex
);
725 for (i
= fd_infos
; i
; i
= i
->next
)
726 if (i
->app_fd
== fd
&& !i
->unusable
) {
731 pthread_mutex_unlock(&fd_infos_mutex
);
736 static void fix_metrics(fd_info
*i
) {
738 char t
[PA_SAMPLE_SPEC_SNPRINT_MAX
];
740 fs
= pa_frame_size(&i
->sample_spec
);
742 /* Don't fix things more than necessary */
743 if ((i
->fragment_size
% fs
) == 0 &&
744 i
->n_fragments
>= 2 &&
745 i
->fragment_size
> 0)
748 i
->fragment_size
= (i
->fragment_size
/fs
)*fs
;
750 /* Number of fragments set? */
751 if (i
->n_fragments
< 2) {
752 if (i
->fragment_size
> 0) {
753 i
->n_fragments
= pa_bytes_per_second(&i
->sample_spec
) / 2 / i
->fragment_size
;
754 if (i
->n_fragments
< 2)
760 /* Fragment size set? */
761 if (i
->fragment_size
<= 0) {
762 i
->fragment_size
= pa_bytes_per_second(&i
->sample_spec
) / 2 / i
->n_fragments
;
763 if (i
->fragment_size
< 1024)
764 i
->fragment_size
= 1024;
767 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": sample spec: %s\n", pa_sample_spec_snprint(t
, sizeof(t
), &i
->sample_spec
));
768 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": fixated metrics to %i fragments, %li bytes each.\n", i
->n_fragments
, (long)i
->fragment_size
);
771 static void stream_request_cb(pa_stream
*s
, size_t length
, void *userdata
) {
772 fd_info
*i
= userdata
;
776 pa_mainloop_api
*api
;
779 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
781 if (s
== i
->play_stream
) {
782 n
= pa_stream_writable_size(i
->play_stream
);
783 if (n
== (size_t)-1) {
784 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_writable_size(): %s\n",
785 pa_strerror(pa_context_errno(i
->context
)));
788 if (n
>= i
->fragment_size
)
789 i
->io_flags
|= PA_IO_EVENT_INPUT
;
791 i
->io_flags
&= ~PA_IO_EVENT_INPUT
;
794 if (s
== i
->rec_stream
) {
795 n
= pa_stream_readable_size(i
->rec_stream
);
796 if (n
== (size_t)-1) {
797 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_readable_size(): %s\n",
798 pa_strerror(pa_context_errno(i
->context
)));
801 if (n
>= i
->fragment_size
)
802 i
->io_flags
|= PA_IO_EVENT_OUTPUT
;
804 i
->io_flags
&= ~PA_IO_EVENT_OUTPUT
;
807 api
->io_enable(i
->io_event
, i
->io_flags
);
811 static void stream_latency_update_cb(pa_stream
*s
, void *userdata
) {
812 fd_info
*i
= userdata
;
815 pa_threaded_mainloop_signal(i
->mainloop
, 0);
818 static void fd_info_shutdown(fd_info
*i
) {
822 pa_mainloop_api
*api
;
823 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
824 api
->io_free(i
->io_event
);
829 if (i
->thread_fd
>= 0) {
835 static int fd_info_copy_data(fd_info
*i
, int force
) {
838 if (!i
->play_stream
&& !i
->rec_stream
)
841 if ((i
->play_stream
) && (pa_stream_get_state(i
->play_stream
) == PA_STREAM_READY
)) {
842 n
= pa_stream_writable_size(i
->play_stream
);
844 if (n
== (size_t)-1) {
845 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_writable_size(): %s\n",
846 pa_strerror(pa_context_errno(i
->context
)));
850 while (n
>= i
->fragment_size
|| force
) {
854 if (!(i
->buf
= malloc(i
->fragment_size
))) {
855 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": malloc() failed.\n");
860 if ((r
= read(i
->thread_fd
, i
->buf
, i
->fragment_size
)) <= 0) {
865 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": read(): %s\n", r
== 0 ? "EOF" : strerror(errno
));
869 if (pa_stream_write(i
->play_stream
, i
->buf
, r
, free
, 0, PA_SEEK_RELATIVE
) < 0) {
870 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
876 assert(n
>= (size_t) r
);
880 if (n
>= i
->fragment_size
)
881 i
->io_flags
|= PA_IO_EVENT_INPUT
;
883 i
->io_flags
&= ~PA_IO_EVENT_INPUT
;
886 if ((i
->rec_stream
) && (pa_stream_get_state(i
->rec_stream
) == PA_STREAM_READY
)) {
887 n
= pa_stream_readable_size(i
->rec_stream
);
889 if (n
== (size_t)-1) {
890 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_readable_size(): %s\n",
891 pa_strerror(pa_context_errno(i
->context
)));
895 while (n
>= i
->fragment_size
|| force
) {
901 if (pa_stream_peek(i
->rec_stream
, &data
, &len
) < 0) {
902 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_peek(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
909 buf
= (const char*)data
+ i
->rec_offset
;
911 if ((r
= write(i
->thread_fd
, buf
, len
- i
->rec_offset
)) <= 0) {
916 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": write(): %s\n", strerror(errno
));
920 assert((size_t)r
<= len
- i
->rec_offset
);
923 if (i
->rec_offset
== len
) {
924 if (pa_stream_drop(i
->rec_stream
) < 0) {
925 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_drop(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
931 assert(n
>= (size_t) r
);
935 if (n
>= i
->fragment_size
)
936 i
->io_flags
|= PA_IO_EVENT_OUTPUT
;
938 i
->io_flags
&= ~PA_IO_EVENT_OUTPUT
;
942 pa_mainloop_api
*api
;
944 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
945 api
->io_enable(i
->io_event
, i
->io_flags
);
951 static void stream_state_cb(pa_stream
*s
, void * userdata
) {
952 fd_info
*i
= userdata
;
955 switch (pa_stream_get_state(s
)) {
957 case PA_STREAM_READY
:
958 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": stream established.\n");
961 case PA_STREAM_FAILED
:
962 if (s
== i
->play_stream
) {
963 debug(DEBUG_LEVEL_NORMAL
,
964 __FILE__
": pa_stream_connect_playback() failed: %s\n",
965 pa_strerror(pa_context_errno(i
->context
)));
966 pa_stream_unref(i
->play_stream
);
967 i
->play_stream
= NULL
;
968 } else if (s
== i
->rec_stream
) {
969 debug(DEBUG_LEVEL_NORMAL
,
970 __FILE__
": pa_stream_connect_record() failed: %s\n",
971 pa_strerror(pa_context_errno(i
->context
)));
972 pa_stream_unref(i
->rec_stream
);
973 i
->rec_stream
= NULL
;
978 case PA_STREAM_TERMINATED
:
979 case PA_STREAM_UNCONNECTED
:
980 case PA_STREAM_CREATING
:
985 static int create_playback_stream(fd_info
*i
) {
993 if (!(i
->play_stream
= pa_stream_new(i
->context
, stream_name(), &i
->sample_spec
, NULL
))) {
994 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
998 pa_stream_set_state_callback(i
->play_stream
, stream_state_cb
, i
);
999 pa_stream_set_write_callback(i
->play_stream
, stream_request_cb
, i
);
1000 pa_stream_set_latency_update_callback(i
->play_stream
, stream_latency_update_cb
, i
);
1002 memset(&attr
, 0, sizeof(attr
));
1003 attr
.maxlength
= i
->fragment_size
* (i
->n_fragments
+1);
1004 attr
.tlength
= i
->fragment_size
* i
->n_fragments
;
1005 attr
.prebuf
= i
->fragment_size
;
1006 attr
.minreq
= i
->fragment_size
;
1008 flags
= PA_STREAM_INTERPOLATE_TIMING
|PA_STREAM_AUTO_TIMING_UPDATE
;
1009 if (i
->play_precork
) {
1010 flags
|= PA_STREAM_START_CORKED
;
1011 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": creating stream corked\n");
1013 if (pa_stream_connect_playback(i
->play_stream
, NULL
, &attr
, flags
, NULL
, NULL
) < 0) {
1014 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
1018 n
= i
->fragment_size
;
1019 setsockopt(i
->app_fd
, SOL_SOCKET
, SO_SNDBUF
, &n
, sizeof(n
));
1020 n
= i
->fragment_size
;
1021 setsockopt(i
->thread_fd
, SOL_SOCKET
, SO_RCVBUF
, &n
, sizeof(n
));
1029 static int create_record_stream(fd_info
*i
) {
1030 pa_buffer_attr attr
;
1037 if (!(i
->rec_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
)));
1042 pa_stream_set_state_callback(i
->rec_stream
, stream_state_cb
, i
);
1043 pa_stream_set_read_callback(i
->rec_stream
, stream_request_cb
, i
);
1044 pa_stream_set_latency_update_callback(i
->rec_stream
, stream_latency_update_cb
, i
);
1046 memset(&attr
, 0, sizeof(attr
));
1047 attr
.maxlength
= i
->fragment_size
* (i
->n_fragments
+1);
1048 attr
.fragsize
= i
->fragment_size
;
1050 flags
= PA_STREAM_INTERPOLATE_TIMING
|PA_STREAM_AUTO_TIMING_UPDATE
;
1051 if (i
->rec_precork
) {
1052 flags
|= PA_STREAM_START_CORKED
;
1053 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": creating stream corked\n");
1055 if (pa_stream_connect_record(i
->rec_stream
, NULL
, &attr
, flags
) < 0) {
1056 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
1060 n
= i
->fragment_size
;
1061 setsockopt(i
->app_fd
, SOL_SOCKET
, SO_RCVBUF
, &n
, sizeof(n
));
1062 n
= i
->fragment_size
;
1063 setsockopt(i
->thread_fd
, SOL_SOCKET
, SO_SNDBUF
, &n
, sizeof(n
));
1071 static void free_streams(fd_info
*i
) {
1074 if (i
->play_stream
) {
1075 pa_stream_disconnect(i
->play_stream
);
1076 pa_stream_unref(i
->play_stream
);
1077 i
->play_stream
= NULL
;
1078 i
->io_flags
|= PA_IO_EVENT_INPUT
;
1081 if (i
->rec_stream
) {
1082 pa_stream_disconnect(i
->rec_stream
);
1083 pa_stream_unref(i
->rec_stream
);
1084 i
->rec_stream
= NULL
;
1085 i
->io_flags
|= PA_IO_EVENT_OUTPUT
;
1089 pa_mainloop_api
*api
;
1091 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
1092 api
->io_enable(i
->io_event
, i
->io_flags
);
1096 static void io_event_cb(pa_mainloop_api
*api
, pa_io_event
*e
, int fd
, pa_io_event_flags_t flags
, void *userdata
) {
1097 fd_info
*i
= userdata
;
1099 pa_threaded_mainloop_signal(i
->mainloop
, 0);
1101 if (flags
& PA_IO_EVENT_INPUT
) {
1103 if (!i
->play_stream
) {
1104 if (create_playback_stream(i
) < 0)
1107 if (fd_info_copy_data(i
, 0) < 0)
1111 } else if (flags
& PA_IO_EVENT_OUTPUT
) {
1113 if (!i
->rec_stream
) {
1114 if (create_record_stream(i
) < 0)
1117 if (fd_info_copy_data(i
, 0) < 0)
1121 } else if (flags
& (PA_IO_EVENT_HANGUP
|PA_IO_EVENT_ERROR
))
1127 /* We can't do anything better than removing the event source */
1128 fd_info_shutdown(i
);
1131 static int dsp_open(int flags
, int *_errno
) {
1133 pa_mainloop_api
*api
;
1137 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": dsp_open()\n");
1139 if (!(i
= fd_info_new(FD_INFO_STREAM
, _errno
)))
1142 if ((flags
& O_NONBLOCK
) == O_NONBLOCK
) {
1143 if ((f
= fcntl(i
->app_fd
, F_GETFL
)) >= 0)
1144 fcntl(i
->app_fd
, F_SETFL
, f
|O_NONBLOCK
);
1146 if ((f
= fcntl(i
->thread_fd
, F_GETFL
)) >= 0)
1147 fcntl(i
->thread_fd
, F_SETFL
, f
|O_NONBLOCK
);
1149 fcntl(i
->app_fd
, F_SETFD
, FD_CLOEXEC
);
1150 fcntl(i
->thread_fd
, F_SETFD
, FD_CLOEXEC
);
1152 pa_threaded_mainloop_lock(i
->mainloop
);
1153 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
1155 switch (flags
& O_ACCMODE
) {
1157 i
->io_flags
= PA_IO_EVENT_OUTPUT
;
1158 shutdown(i
->thread_fd
, SHUT_RD
);
1159 shutdown(i
->app_fd
, SHUT_WR
);
1162 i
->io_flags
= PA_IO_EVENT_INPUT
;
1163 shutdown(i
->thread_fd
, SHUT_WR
);
1164 shutdown(i
->app_fd
, SHUT_RD
);
1167 i
->io_flags
= PA_IO_EVENT_INPUT
| PA_IO_EVENT_OUTPUT
;
1173 if (!(i
->io_event
= api
->io_new(api
, i
->thread_fd
, i
->io_flags
, io_event_cb
, i
)))
1176 pa_threaded_mainloop_unlock(i
->mainloop
);
1178 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": dsp_open() succeeded, fd=%i\n", i
->app_fd
);
1180 fd_info_add_to_list(i
);
1187 pa_threaded_mainloop_unlock(i
->mainloop
);
1194 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": dsp_open() failed\n");
1199 static void sink_info_cb(pa_context
*context
, const pa_sink_info
*si
, int eol
, void *userdata
) {
1200 fd_info
*i
= userdata
;
1202 if (!si
&& eol
< 0) {
1203 i
->operation_success
= 0;
1204 pa_threaded_mainloop_signal(i
->mainloop
, 0);
1211 if (!pa_cvolume_equal(&i
->sink_volume
, &si
->volume
))
1212 i
->volume_modify_count
++;
1214 i
->sink_volume
= si
->volume
;
1215 i
->sink_index
= si
->index
;
1217 i
->operation_success
= 1;
1218 pa_threaded_mainloop_signal(i
->mainloop
, 0);
1221 static void source_info_cb(pa_context
*context
, const pa_source_info
*si
, int eol
, void *userdata
) {
1222 fd_info
*i
= userdata
;
1224 if (!si
&& eol
< 0) {
1225 i
->operation_success
= 0;
1226 pa_threaded_mainloop_signal(i
->mainloop
, 0);
1233 if (!pa_cvolume_equal(&i
->source_volume
, &si
->volume
))
1234 i
->volume_modify_count
++;
1236 i
->source_volume
= si
->volume
;
1237 i
->source_index
= si
->index
;
1239 i
->operation_success
= 1;
1240 pa_threaded_mainloop_signal(i
->mainloop
, 0);
1243 static void subscribe_cb(pa_context
*context
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1244 fd_info
*i
= userdata
;
1245 pa_operation
*o
= NULL
;
1247 if (i
->sink_index
!= idx
)
1250 if ((t
& PA_SUBSCRIPTION_EVENT_TYPE_MASK
) != PA_SUBSCRIPTION_EVENT_CHANGE
)
1253 if (!(o
= pa_context_get_sink_info_by_index(i
->context
, i
->sink_index
, sink_info_cb
, i
))) {
1254 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to get sink info: %s", pa_strerror(pa_context_errno(i
->context
)));
1258 pa_operation_unref(o
);
1261 static int mixer_open(int flags
, int *_errno
) {
1263 pa_operation
*o
= NULL
;
1266 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": mixer_open()\n");
1268 if (!(i
= fd_info_new(FD_INFO_MIXER
, _errno
)))
1271 pa_threaded_mainloop_lock(i
->mainloop
);
1273 pa_context_set_subscribe_callback(i
->context
, subscribe_cb
, i
);
1275 if (!(o
= pa_context_subscribe(i
->context
, PA_SUBSCRIPTION_MASK_SINK
| PA_SUBSCRIPTION_MASK_SOURCE
, context_success_cb
, i
))) {
1276 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i
->context
)));
1281 i
->operation_success
= 0;
1282 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1283 pa_threaded_mainloop_wait(i
->mainloop
);
1284 CONTEXT_CHECK_DEAD_GOTO(i
, fail
);
1287 pa_operation_unref(o
);
1290 if (!i
->operation_success
) {
1291 debug(DEBUG_LEVEL_NORMAL
, __FILE__
":Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i
->context
)));
1298 if (!(o
= pa_context_get_sink_info_by_name(i
->context
, NULL
, sink_info_cb
, i
))) {
1299 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to get sink info: %s", pa_strerror(pa_context_errno(i
->context
)));
1304 i
->operation_success
= 0;
1305 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1306 pa_threaded_mainloop_wait(i
->mainloop
);
1307 CONTEXT_CHECK_DEAD_GOTO(i
, fail
);
1310 pa_operation_unref(o
);
1313 if (!i
->operation_success
) {
1314 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to get sink info: %s", pa_strerror(pa_context_errno(i
->context
)));
1319 /* Get source info */
1321 if (!(o
= pa_context_get_source_info_by_name(i
->context
, NULL
, source_info_cb
, i
))) {
1322 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to get source info: %s", pa_strerror(pa_context_errno(i
->context
)));
1327 i
->operation_success
= 0;
1328 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1329 pa_threaded_mainloop_wait(i
->mainloop
);
1330 CONTEXT_CHECK_DEAD_GOTO(i
, fail
);
1333 pa_operation_unref(o
);
1336 if (!i
->operation_success
) {
1337 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to get source info: %s", pa_strerror(pa_context_errno(i
->context
)));
1342 pa_threaded_mainloop_unlock(i
->mainloop
);
1344 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": mixer_open() succeeded, fd=%i\n", i
->app_fd
);
1346 fd_info_add_to_list(i
);
1354 pa_operation_unref(o
);
1356 pa_threaded_mainloop_unlock(i
->mainloop
);
1363 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": mixer_open() failed\n");
1368 static int sndstat_open(int flags
, int *_errno
) {
1369 static const char sndstat
[] =
1370 "Sound Driver:3.8.1a-980706 (PulseAudio Virtual OSS)\n"
1372 "Config options: 0\n"
1374 "Installed drivers:\n"
1375 "Type 255: PulseAudio Virtual OSS\n"
1378 "PulseAudio Virtual OSS\n"
1381 "0: PulseAudio Virtual OSS\n"
1383 "Synth devices: NOT ENABLED IN CONFIG\n"
1390 "0: PulseAudio Virtual OSS\n";
1392 char fn
[] = "/tmp/padsp-sndstat-XXXXXX";
1397 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": sndstat_open()\n");
1399 if (flags
!= O_RDONLY
1401 && flags
!= (O_RDONLY
|O_LARGEFILE
)
1405 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": bad access!\n");
1416 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": mkstemp() failed: %s\n", strerror(errno
));
1422 if (write(fd
, sndstat
, sizeof(sndstat
) -1) != sizeof(sndstat
)-1) {
1424 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": write() failed: %s\n", strerror(errno
));
1428 if (lseek(fd
, SEEK_SET
, 0) < 0) {
1430 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": lseek() failed: %s\n", strerror(errno
));
1442 static int real_open(const char *filename
, int flags
, mode_t mode
) {
1445 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": open(%s)\n", filename
?filename
:"NULL");
1447 if (!function_enter()) {
1449 return _open(filename
, flags
, mode
);
1452 if (filename
&& dsp_cloak_enable() && (strcmp(filename
, "/dev/dsp") == 0 || strcmp(filename
, "/dev/adsp") == 0))
1453 r
= dsp_open(flags
, &_errno
);
1454 else if (filename
&& mixer_cloak_enable() && strcmp(filename
, "/dev/mixer") == 0)
1455 r
= mixer_open(flags
, &_errno
);
1456 else if (filename
&& sndstat_cloak_enable() && strcmp(filename
, "/dev/sndstat") == 0)
1457 r
= sndstat_open(flags
, &_errno
);
1461 return _open(filename
, flags
, mode
);
1472 int open(const char *filename
, int flags
, ...) {
1476 if (flags
& O_CREAT
) {
1477 va_start(args
, flags
);
1478 if (sizeof(mode_t
) < sizeof(int))
1479 mode
= va_arg(args
, int);
1481 mode
= va_arg(args
, mode_t
);
1485 return real_open(filename
, flags
, mode
);
1488 static int mixer_ioctl(fd_info
*i
, unsigned long request
, void*argp
, int *_errno
) {
1492 case SOUND_MIXER_READ_DEVMASK
:
1493 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_DEVMASK\n");
1495 *(int*) argp
= SOUND_MASK_PCM
| SOUND_MASK_IGAIN
;
1498 case SOUND_MIXER_READ_RECMASK
:
1499 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_RECMASK\n");
1501 *(int*) argp
= SOUND_MASK_IGAIN
;
1504 case SOUND_MIXER_READ_STEREODEVS
:
1505 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_STEREODEVS\n");
1507 pa_threaded_mainloop_lock(i
->mainloop
);
1509 if (i
->sink_volume
.channels
> 1)
1510 *(int*) argp
|= SOUND_MASK_PCM
;
1511 if (i
->source_volume
.channels
> 1)
1512 *(int*) argp
|= SOUND_MASK_IGAIN
;
1513 pa_threaded_mainloop_unlock(i
->mainloop
);
1517 case SOUND_MIXER_READ_RECSRC
:
1518 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_RECSRC\n");
1520 *(int*) argp
= SOUND_MASK_IGAIN
;
1523 case SOUND_MIXER_WRITE_RECSRC
:
1524 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_WRITE_RECSRC\n");
1527 case SOUND_MIXER_READ_CAPS
:
1528 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_CAPS\n");
1533 case SOUND_MIXER_READ_PCM
:
1534 case SOUND_MIXER_READ_IGAIN
: {
1537 if (request
== SOUND_MIXER_READ_PCM
)
1538 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_PCM\n");
1540 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_IGAIN\n");
1542 pa_threaded_mainloop_lock(i
->mainloop
);
1544 if (request
== SOUND_MIXER_READ_PCM
)
1545 v
= &i
->sink_volume
;
1547 v
= &i
->source_volume
;
1550 ((v
->values
[0]*100/PA_VOLUME_NORM
)) |
1551 ((v
->values
[v
->channels
> 1 ? 1 : 0]*100/PA_VOLUME_NORM
) << 8);
1553 pa_threaded_mainloop_unlock(i
->mainloop
);
1558 case SOUND_MIXER_WRITE_PCM
:
1559 case SOUND_MIXER_WRITE_IGAIN
: {
1562 if (request
== SOUND_MIXER_WRITE_PCM
)
1563 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_WRITE_PCM\n");
1565 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_WRITE_IGAIN\n");
1567 pa_threaded_mainloop_lock(i
->mainloop
);
1569 if (request
== SOUND_MIXER_WRITE_PCM
) {
1571 pv
= &i
->sink_volume
;
1573 v
= i
->source_volume
;
1574 pv
= &i
->source_volume
;
1577 pv
->values
[0] = ((*(int*) argp
& 0xFF)*PA_VOLUME_NORM
)/100;
1578 pv
->values
[1] = ((*(int*) argp
>> 8)*PA_VOLUME_NORM
)/100;
1580 if (!pa_cvolume_equal(pv
, &v
)) {
1583 if (request
== SOUND_MIXER_WRITE_PCM
)
1584 o
= pa_context_set_sink_volume_by_index(i
->context
, i
->sink_index
, pv
, context_success_cb
, i
);
1586 o
= pa_context_set_source_volume_by_index(i
->context
, i
->source_index
, pv
, context_success_cb
, i
);
1589 debug(DEBUG_LEVEL_NORMAL
, __FILE__
":Failed set volume: %s", pa_strerror(pa_context_errno(i
->context
)));
1592 i
->operation_success
= 0;
1593 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1594 CONTEXT_CHECK_DEAD_GOTO(i
, exit_loop
);
1596 pa_threaded_mainloop_wait(i
->mainloop
);
1600 if (!i
->operation_success
)
1601 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to set volume: %s\n", pa_strerror(pa_context_errno(i
->context
)));
1603 pa_operation_unref(o
);
1606 /* We don't wait for completion here */
1607 i
->volume_modify_count
++;
1610 pa_threaded_mainloop_unlock(i
->mainloop
);
1615 case SOUND_MIXER_INFO
: {
1616 mixer_info
*mi
= argp
;
1618 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_INFO\n");
1620 memset(mi
, 0, sizeof(mixer_info
));
1621 strncpy(mi
->id
, "PULSEAUDIO", sizeof(mi
->id
));
1622 strncpy(mi
->name
, "PulseAudio Virtual OSS", sizeof(mi
->name
));
1623 pa_threaded_mainloop_lock(i
->mainloop
);
1624 mi
->modify_counter
= i
->volume_modify_count
;
1625 pa_threaded_mainloop_unlock(i
->mainloop
);
1630 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": unknown ioctl 0x%08lx\n", request
);
1643 static int map_format(int *fmt
, pa_sample_spec
*ss
) {
1647 ss
->format
= PA_SAMPLE_ULAW
;
1651 ss
->format
= PA_SAMPLE_ALAW
;
1658 ss
->format
= PA_SAMPLE_U8
;
1665 ss
->format
= PA_SAMPLE_S16BE
;
1672 ss
->format
= PA_SAMPLE_S16LE
;
1676 ss
->format
= PA_SAMPLE_S16NE
;
1684 static int map_format_back(pa_sample_format_t format
) {
1686 case PA_SAMPLE_S16LE
: return AFMT_S16_LE
;
1687 case PA_SAMPLE_S16BE
: return AFMT_S16_BE
;
1688 case PA_SAMPLE_ULAW
: return AFMT_MU_LAW
;
1689 case PA_SAMPLE_ALAW
: return AFMT_A_LAW
;
1690 case PA_SAMPLE_U8
: return AFMT_U8
;
1696 static int dsp_flush_fd(int fd
) {
1700 if (ioctl(fd
, SIOCINQ
, &l
) < 0) {
1701 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SIOCINQ: %s\n", strerror(errno
));
1709 k
= (size_t) l
> sizeof(buf
) ? sizeof(buf
) : (size_t) l
;
1710 if (read(fd
, buf
, k
) < 0)
1711 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": read(): %s\n", strerror(errno
));
1717 # warning "Your platform does not support SIOCINQ, something might not work as intended."
1722 static int dsp_flush_socket(fd_info
*i
) {
1725 if ((i
->thread_fd
< 0) && (i
->app_fd
< 0))
1728 if (i
->thread_fd
>= 0)
1729 res
= dsp_flush_fd(i
->thread_fd
);
1735 res
= dsp_flush_fd(i
->app_fd
);
1743 static int dsp_empty_socket(fd_info
*i
) {
1747 /* Empty the socket */
1751 if (i
->thread_fd
< 0)
1754 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0) {
1755 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SIOCINQ: %s\n", strerror(errno
));
1764 pa_threaded_mainloop_wait(i
->mainloop
);
1769 # warning "Your platform does not support SIOCINQ, something might not work as intended."
1774 static int dsp_drain(fd_info
*i
) {
1775 pa_operation
*o
= NULL
;
1781 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Draining.\n");
1783 pa_threaded_mainloop_lock(i
->mainloop
);
1785 if (dsp_empty_socket(i
) < 0)
1788 if (!i
->play_stream
)
1791 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Really draining.\n");
1793 if (!(o
= pa_stream_drain(i
->play_stream
, stream_success_cb
, i
))) {
1794 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1798 i
->operation_success
= 0;
1799 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1800 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i
, fail
);
1802 pa_threaded_mainloop_wait(i
->mainloop
);
1805 if (!i
->operation_success
) {
1806 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i
->context
)));
1815 pa_operation_unref(o
);
1817 pa_threaded_mainloop_unlock(i
->mainloop
);
1822 static int dsp_trigger(fd_info
*i
) {
1823 pa_operation
*o
= NULL
;
1826 if (!i
->play_stream
)
1829 pa_threaded_mainloop_lock(i
->mainloop
);
1831 if (dsp_empty_socket(i
) < 0)
1834 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Triggering.\n");
1836 if (!(o
= pa_stream_trigger(i
->play_stream
, stream_success_cb
, i
))) {
1837 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1841 i
->operation_success
= 0;
1842 while (!pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1843 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i
, fail
);
1845 pa_threaded_mainloop_wait(i
->mainloop
);
1848 if (!i
->operation_success
) {
1849 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1858 pa_operation_unref(o
);
1860 pa_threaded_mainloop_unlock(i
->mainloop
);
1865 static int dsp_cork(fd_info
*i
, pa_stream
*s
, int b
) {
1866 pa_operation
*o
= NULL
;
1869 pa_threaded_mainloop_lock(i
->mainloop
);
1871 if (!(o
= pa_stream_cork(s
, b
, stream_success_cb
, i
))) {
1872 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_cork(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1876 i
->operation_success
= 0;
1877 while (!pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1878 if (s
== i
->play_stream
)
1879 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i
, fail
);
1880 else if (s
== i
->rec_stream
)
1881 RECORD_STREAM_CHECK_DEAD_GOTO(i
, fail
);
1883 pa_threaded_mainloop_wait(i
->mainloop
);
1886 if (!i
->operation_success
) {
1887 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_cork(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1896 pa_operation_unref(o
);
1898 pa_threaded_mainloop_unlock(i
->mainloop
);
1903 static int dsp_ioctl(fd_info
*i
, unsigned long request
, void*argp
, int *_errno
) {
1906 if (i
->thread_fd
== -1) {
1908 * We've encountered some fatal error and are just waiting
1911 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": got ioctl 0x%08lx in fatal error state\n", request
);
1917 case SNDCTL_DSP_SETFMT
: {
1918 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp
);
1920 pa_threaded_mainloop_lock(i
->mainloop
);
1922 if (*(int*) argp
== AFMT_QUERY
)
1923 *(int*) argp
= map_format_back(i
->sample_spec
.format
);
1925 map_format((int*) argp
, &i
->sample_spec
);
1929 pa_threaded_mainloop_unlock(i
->mainloop
);
1933 case SNDCTL_DSP_SPEED
: {
1938 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SPEED: %i\n", *(int*) argp
);
1940 pa_threaded_mainloop_lock(i
->mainloop
);
1942 ss
= i
->sample_spec
;
1943 ss
.rate
= *(int*) argp
;
1945 if ((valid
= pa_sample_spec_valid(&ss
))) {
1946 i
->sample_spec
= ss
;
1950 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": ss: %s\n", pa_sample_spec_snprint(t
, sizeof(t
), &i
->sample_spec
));
1952 pa_threaded_mainloop_unlock(i
->mainloop
);
1962 case SNDCTL_DSP_STEREO
:
1963 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_STEREO: %i\n", *(int*) argp
);
1965 pa_threaded_mainloop_lock(i
->mainloop
);
1967 i
->sample_spec
.channels
= *(int*) argp
? 2 : 1;
1970 pa_threaded_mainloop_unlock(i
->mainloop
);
1973 case SNDCTL_DSP_CHANNELS
: {
1977 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp
);
1979 pa_threaded_mainloop_lock(i
->mainloop
);
1981 ss
= i
->sample_spec
;
1982 ss
.channels
= *(int*) argp
;
1984 if ((valid
= pa_sample_spec_valid(&ss
))) {
1985 i
->sample_spec
= ss
;
1989 pa_threaded_mainloop_unlock(i
->mainloop
);
1999 case SNDCTL_DSP_GETBLKSIZE
:
2000 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETBLKSIZE\n");
2002 pa_threaded_mainloop_lock(i
->mainloop
);
2005 *(int*) argp
= i
->fragment_size
;
2007 pa_threaded_mainloop_unlock(i
->mainloop
);
2011 case SNDCTL_DSP_SETFRAGMENT
:
2012 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SETFRAGMENT: 0x%08x\n", *(int*) argp
);
2014 pa_threaded_mainloop_lock(i
->mainloop
);
2016 i
->fragment_size
= 1 << ((*(int*) argp
) & 31);
2017 i
->n_fragments
= (*(int*) argp
) >> 16;
2019 /* 0x7FFF means that we can set whatever we like */
2020 if (i
->n_fragments
== 0x7FFF)
2021 i
->n_fragments
= 12;
2025 pa_threaded_mainloop_unlock(i
->mainloop
);
2029 case SNDCTL_DSP_GETCAPS
:
2030 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_CAPS\n");
2032 *(int*) argp
= DSP_CAP_DUPLEX
| DSP_CAP_TRIGGER
2033 #ifdef DSP_CAP_MULTI
2039 case SNDCTL_DSP_GETODELAY
: {
2042 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETODELAY\n");
2044 pa_threaded_mainloop_lock(i
->mainloop
);
2051 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i
, exit_loop
);
2053 if (pa_stream_get_latency(i
->play_stream
, &usec
, NULL
) >= 0) {
2054 *(int*) argp
= pa_usec_to_bytes(usec
, &i
->sample_spec
);
2058 if (pa_context_errno(i
->context
) != PA_ERR_NODATA
) {
2059 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
2063 pa_threaded_mainloop_wait(i
->mainloop
);
2069 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0)
2070 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SIOCINQ failed: %s\n", strerror(errno
));
2074 # warning "Your platform does not support SIOCINQ, something might not work as intended."
2077 pa_threaded_mainloop_unlock(i
->mainloop
);
2079 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": ODELAY: %i\n", *(int*) argp
);
2084 case SNDCTL_DSP_RESET
: {
2085 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_RESET\n");
2087 pa_threaded_mainloop_lock(i
->mainloop
);
2090 dsp_flush_socket(i
);
2092 i
->optr_n_blocks
= 0;
2094 pa_threaded_mainloop_unlock(i
->mainloop
);
2098 case SNDCTL_DSP_GETFMTS
: {
2099 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETFMTS\n");
2101 *(int*) argp
= AFMT_MU_LAW
|AFMT_A_LAW
|AFMT_U8
|AFMT_S16_LE
|AFMT_S16_BE
;
2105 case SNDCTL_DSP_POST
:
2106 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_POST\n");
2108 if (dsp_trigger(i
) < 0)
2112 case SNDCTL_DSP_GETTRIGGER
:
2113 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETTRIGGER\n");
2116 if (!i
->play_precork
)
2117 *(int*) argp
|= PCM_ENABLE_OUTPUT
;
2118 if (!i
->rec_precork
)
2119 *(int*) argp
|= PCM_ENABLE_INPUT
;
2123 case SNDCTL_DSP_SETTRIGGER
:
2124 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SETTRIGGER: 0x%08x\n", *(int*) argp
);
2131 i
->play_precork
= !((*(int*) argp
) & PCM_ENABLE_OUTPUT
);
2133 if (i
->play_stream
) {
2134 if (dsp_cork(i
, i
->play_stream
, !((*(int*) argp
) & PCM_ENABLE_OUTPUT
)) < 0)
2136 if (dsp_trigger(i
) < 0)
2140 i
->rec_precork
= !((*(int*) argp
) & PCM_ENABLE_INPUT
);
2142 if (i
->rec_stream
) {
2143 if (dsp_cork(i
, i
->rec_stream
, !((*(int*) argp
) & PCM_ENABLE_INPUT
)) < 0)
2149 case SNDCTL_DSP_SYNC
:
2150 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SYNC\n");
2152 if (dsp_drain(i
) < 0)
2157 case SNDCTL_DSP_GETOSPACE
:
2158 case SNDCTL_DSP_GETISPACE
: {
2159 audio_buf_info
*bi
= (audio_buf_info
*) argp
;
2163 if (request
== SNDCTL_DSP_GETOSPACE
)
2164 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETOSPACE\n");
2166 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETISPACE\n");
2168 pa_threaded_mainloop_lock(i
->mainloop
);
2172 if (request
== SNDCTL_DSP_GETOSPACE
) {
2173 if (i
->play_stream
) {
2174 if ((k
= pa_stream_writable_size(i
->play_stream
)) == (size_t) -1)
2175 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
2177 k
= i
->fragment_size
* i
->n_fragments
;
2180 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0) {
2181 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SIOCINQ failed: %s\n", strerror(errno
));
2185 # warning "Your platform does not dsp_flush_fd, something might not work as intended."
2188 bi
->bytes
= k
> (size_t) l
? k
- l
: 0;
2190 if (i
->rec_stream
) {
2191 if ((k
= pa_stream_readable_size(i
->rec_stream
)) == (size_t) -1)
2192 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_readable_size(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
2197 if (ioctl(i
->app_fd
, SIOCINQ
, &l
) < 0) {
2198 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SIOCINQ failed: %s\n", strerror(errno
));
2202 # warning "Your platform does not dsp_flush_fd, something might not work as intended."
2207 bi
->fragsize
= i
->fragment_size
;
2208 bi
->fragstotal
= i
->n_fragments
;
2209 bi
->fragments
= bi
->bytes
/ bi
->fragsize
;
2211 pa_threaded_mainloop_unlock(i
->mainloop
);
2213 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi
->fragsize
, bi
->fragstotal
, bi
->bytes
, bi
->fragments
);
2218 case SOUND_PCM_READ_RATE
:
2219 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_PCM_READ_RATE\n");
2221 pa_threaded_mainloop_lock(i
->mainloop
);
2222 *(int*) argp
= i
->sample_spec
.rate
;
2223 pa_threaded_mainloop_unlock(i
->mainloop
);
2226 case SOUND_PCM_READ_CHANNELS
:
2227 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_PCM_READ_CHANNELS\n");
2229 pa_threaded_mainloop_lock(i
->mainloop
);
2230 *(int*) argp
= i
->sample_spec
.channels
;
2231 pa_threaded_mainloop_unlock(i
->mainloop
);
2234 case SOUND_PCM_READ_BITS
:
2235 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_PCM_READ_BITS\n");
2237 pa_threaded_mainloop_lock(i
->mainloop
);
2238 *(int*) argp
= pa_sample_size(&i
->sample_spec
)*8;
2239 pa_threaded_mainloop_unlock(i
->mainloop
);
2242 case SNDCTL_DSP_GETOPTR
: {
2245 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETOPTR\n");
2247 info
= (count_info
*) argp
;
2248 memset(info
, 0, sizeof(*info
));
2250 pa_threaded_mainloop_lock(i
->mainloop
);
2255 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i
, exit_loop
);
2257 if (pa_stream_get_time(i
->play_stream
, &usec
) >= 0) {
2258 size_t k
= pa_usec_to_bytes(usec
, &i
->sample_spec
);
2261 info
->bytes
= (int) k
;
2262 m
= k
/ i
->fragment_size
;
2263 info
->blocks
= m
- i
->optr_n_blocks
;
2264 i
->optr_n_blocks
= m
;
2269 if (pa_context_errno(i
->context
) != PA_ERR_NODATA
) {
2270 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
2274 pa_threaded_mainloop_wait(i
->mainloop
);
2277 pa_threaded_mainloop_unlock(i
->mainloop
);
2279 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": GETOPTR bytes=%i, blocks=%i, ptr=%i\n", info
->bytes
, info
->blocks
, info
->ptr
);
2284 case SNDCTL_DSP_GETIPTR
:
2285 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": invalid ioctl SNDCTL_DSP_GETIPTR\n");
2288 case SNDCTL_DSP_SETDUPLEX
:
2289 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SETDUPLEX\n");
2290 /* this is a no-op */
2294 /* Mixer ioctls are valid on /dev/dsp aswell */
2295 return mixer_ioctl(i
, request
, argp
, _errno
);
2310 int ioctl(int fd
, int request
, ...) {
2312 int ioctl(int fd
, unsigned long request
, ...) {
2319 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": ioctl()\n");
2321 va_start(args
, request
);
2322 argp
= va_arg(args
, void *);
2325 if (!function_enter()) {
2327 return _ioctl(fd
, request
, argp
);
2330 if (!(i
= fd_info_find(fd
))) {
2333 return _ioctl(fd
, request
, argp
);
2336 if (i
->type
== FD_INFO_MIXER
)
2337 r
= mixer_ioctl(i
, request
, argp
, &_errno
);
2339 r
= dsp_ioctl(i
, request
, argp
, &_errno
);
2354 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": close()\n");
2356 if (!function_enter()) {
2361 if (!(i
= fd_info_find(fd
))) {
2367 fd_info_remove_from_list(i
);
2375 int access(const char *pathname
, int mode
) {
2377 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": access(%s)\n", pathname
?pathname
:"NULL");
2380 ( strcmp(pathname
, "/dev/dsp") != 0 &&
2381 strcmp(pathname
, "/dev/adsp") != 0 &&
2382 strcmp(pathname
, "/dev/sndstat") != 0 &&
2383 strcmp(pathname
, "/dev/mixer") != 0 )) {
2385 return _access(pathname
, mode
);
2388 if (mode
& (W_OK
| X_OK
)) {
2389 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": access(%s, %x) = EACCESS\n", pathname
, mode
);
2394 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": access(%s, %x) = OK\n", pathname
, mode
);
2399 int stat(const char *pathname
, struct stat
*buf
) {
2401 struct stat64 parent
;
2409 ( strcmp(pathname
, "/dev/dsp") != 0 &&
2410 strcmp(pathname
, "/dev/adsp") != 0 &&
2411 strcmp(pathname
, "/dev/sndstat") != 0 &&
2412 strcmp(pathname
, "/dev/mixer") != 0 )) {
2413 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": stat(%s)\n", pathname
?pathname
:"NULL");
2415 return _stat(pathname
, buf
);
2418 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": stat(%s)\n", pathname
);
2422 ret
= __xstat64(_STAT_VER
, "/dev", &parent
);
2424 ret
= __xstat(_STAT_VER
, "/dev", &parent
);
2428 ret
= stat64("/dev", &parent
);
2430 ret
= stat("/dev", &parent
);
2435 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": unable to stat \"/dev\"\n");
2439 buf
->st_dev
= parent
.st_dev
;
2440 buf
->st_ino
= 0xDEADBEEF; /* FIXME: Can we do this in a safe way? */
2441 buf
->st_mode
= S_IFCHR
| S_IRUSR
| S_IWUSR
;
2443 buf
->st_uid
= getuid();
2444 buf
->st_gid
= getgid();
2445 buf
->st_rdev
= 0x0E03; /* FIXME: Linux specific */
2447 buf
->st_atime
= 1181557705;
2448 buf
->st_mtime
= 1181557705;
2449 buf
->st_ctime
= 1181557705;
2450 buf
->st_blksize
= 1;
2458 int stat64(const char *pathname
, struct stat64
*buf
) {
2462 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": stat64(%s)\n", pathname
?pathname
:"NULL");
2466 ( strcmp(pathname
, "/dev/dsp") != 0 &&
2467 strcmp(pathname
, "/dev/adsp") != 0 &&
2468 strcmp(pathname
, "/dev/sndstat") != 0 &&
2469 strcmp(pathname
, "/dev/mixer") != 0 )) {
2471 return _stat64(pathname
, buf
);
2474 ret
= stat(pathname
, &oldbuf
);
2478 buf
->st_dev
= oldbuf
.st_dev
;
2479 buf
->st_ino
= oldbuf
.st_ino
;
2480 buf
->st_mode
= oldbuf
.st_mode
;
2481 buf
->st_nlink
= oldbuf
.st_nlink
;
2482 buf
->st_uid
= oldbuf
.st_uid
;
2483 buf
->st_gid
= oldbuf
.st_gid
;
2484 buf
->st_rdev
= oldbuf
.st_rdev
;
2485 buf
->st_size
= oldbuf
.st_size
;
2486 buf
->st_atime
= oldbuf
.st_atime
;
2487 buf
->st_mtime
= oldbuf
.st_mtime
;
2488 buf
->st_ctime
= oldbuf
.st_ctime
;
2489 buf
->st_blksize
= oldbuf
.st_blksize
;
2490 buf
->st_blocks
= oldbuf
.st_blocks
;
2495 int open64(const char *filename
, int flags
, ...) {
2499 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": open64(%s)\n", filename
?filename
:"NULL");
2501 if (flags
& O_CREAT
) {
2502 va_start(args
, flags
);
2503 if (sizeof(mode_t
) < sizeof(int))
2504 mode
= va_arg(args
, int);
2506 mode
= va_arg(args
, mode_t
);
2511 ( strcmp(filename
, "/dev/dsp") != 0 &&
2512 strcmp(filename
, "/dev/adsp") != 0 &&
2513 strcmp(filename
, "/dev/sndstat") != 0 &&
2514 strcmp(filename
, "/dev/mixer") != 0 )) {
2516 return _open64(filename
, flags
, mode
);
2519 return real_open(filename
, flags
, mode
);
2526 int __xstat(int ver
, const char *pathname
, struct stat
*buf
) {
2527 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": __xstat(%s)\n", pathname
?pathname
:"NULL");
2531 ( strcmp(pathname
, "/dev/dsp") != 0 &&
2532 strcmp(pathname
, "/dev/adsp") != 0 &&
2533 strcmp(pathname
, "/dev/sndstat") != 0 &&
2534 strcmp(pathname
, "/dev/mixer") != 0 )) {
2536 return ___xstat(ver
, pathname
, buf
);
2539 if (ver
!= _STAT_VER
) {
2544 return stat(pathname
, buf
);
2549 int __xstat64(int ver
, const char *pathname
, struct stat64
*buf
) {
2550 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": __xstat64(%s)\n", pathname
?pathname
:"NULL");
2554 ( strcmp(pathname
, "/dev/dsp") != 0 &&
2555 strcmp(pathname
, "/dev/adsp") != 0 &&
2556 strcmp(pathname
, "/dev/sndstat") != 0 &&
2557 strcmp(pathname
, "/dev/mixer") != 0 )) {
2558 LOAD_XSTAT64_FUNC();
2559 return ___xstat64(ver
, pathname
, buf
);
2562 if (ver
!= _STAT_VER
) {
2567 return stat64(pathname
, buf
);
2574 FILE* fopen(const char *filename
, const char *mode
) {
2579 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": fopen(%s)\n", filename
?filename
:"NULL");
2583 ( strcmp(filename
, "/dev/dsp") != 0 &&
2584 strcmp(filename
, "/dev/adsp") != 0 &&
2585 strcmp(filename
, "/dev/sndstat") != 0 &&
2586 strcmp(filename
, "/dev/mixer") != 0 )) {
2588 return _fopen(filename
, mode
);
2604 if ((((mode
[1] == 'b') || (mode
[1] == 't')) && (mode
[2] == '+')) || (mode
[1] == '+'))
2607 if ((fd
= real_open(filename
, m
, 0)) < 0)
2610 if (!(f
= fdopen(fd
, mode
))) {
2620 FILE *fopen64(const char *filename
, const char *mode
) {
2622 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": fopen64(%s)\n", filename
?filename
:"NULL");
2626 ( strcmp(filename
, "/dev/dsp") != 0 &&
2627 strcmp(filename
, "/dev/adsp") != 0 &&
2628 strcmp(filename
, "/dev/sndstat") != 0 &&
2629 strcmp(filename
, "/dev/mixer") != 0 )) {
2630 LOAD_FOPEN64_FUNC();
2631 return _fopen64(filename
, mode
);
2634 return fopen(filename
, mode
);
2639 int fclose(FILE *f
) {
2642 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": fclose()\n");
2644 if (!function_enter()) {
2649 if (!(i
= fd_info_find(fileno(f
)))) {
2655 fd_info_remove_from_list(i
);
2657 /* Dirty trick to avoid that the fd is not freed twice, once by us
2658 * and once by the real fclose() */