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
69 typedef struct fd_info fd_info
;
72 pthread_mutex_t mutex
;
77 int app_fd
, thread_fd
;
79 pa_sample_spec sample_spec
;
83 pa_threaded_mainloop
*mainloop
;
85 pa_stream
*play_stream
;
86 pa_stream
*rec_stream
;
90 pa_io_event
*io_event
;
91 pa_io_event_flags_t io_flags
;
96 int operation_success
;
98 pa_cvolume sink_volume
, source_volume
;
99 uint32_t sink_index
, source_index
;
100 int volume_modify_count
;
104 PA_LLIST_FIELDS(fd_info
);
107 static int dsp_drain(fd_info
*i
);
108 static void fd_info_remove_from_list(fd_info
*i
);
110 static pthread_mutex_t fd_infos_mutex
= PTHREAD_MUTEX_INITIALIZER
;
111 static pthread_mutex_t func_mutex
= PTHREAD_MUTEX_INITIALIZER
;
113 static PA_LLIST_HEAD(fd_info
, fd_infos
) = NULL
;
115 static int (*_ioctl
)(int, int, void*) = NULL
;
116 static int (*_close
)(int) = NULL
;
117 static int (*_open
)(const char *, int, mode_t
) = NULL
;
118 static FILE* (*_fopen
)(const char *path
, const char *mode
) = NULL
;
119 static int (*_stat
)(const char *, struct stat
*) = NULL
;
121 static int (*___xstat
)(int, const char *, struct stat
*) = NULL
;
124 static int (*_open64
)(const char *, int, mode_t
) = NULL
;
125 static FILE* (*_fopen64
)(const char *path
, const char *mode
) = NULL
;
126 static int (*_stat64
)(const char *, struct stat64
*) = NULL
;
128 static int (*___xstat64
)(int, const char *, struct stat64
*) = NULL
;
131 static int (*_fclose
)(FILE *f
) = NULL
;
132 static int (*_access
)(const char *, int) = NULL
;
134 /* dlsym() violates ISO C, so confide the breakage into this function to
136 typedef void (*fnptr
)(void);
137 static inline fnptr
dlsym_fn(void *handle
, const char *symbol
) {
138 return (fnptr
) (long) dlsym(handle
, symbol
);
141 #define LOAD_IOCTL_FUNC() \
143 pthread_mutex_lock(&func_mutex); \
145 _ioctl = (int (*)(int, int, void*)) dlsym_fn(RTLD_NEXT, "ioctl"); \
146 pthread_mutex_unlock(&func_mutex); \
149 #define LOAD_OPEN_FUNC() \
151 pthread_mutex_lock(&func_mutex); \
153 _open = (int (*)(const char *, int, mode_t)) dlsym_fn(RTLD_NEXT, "open"); \
154 pthread_mutex_unlock(&func_mutex); \
157 #define LOAD_OPEN64_FUNC() \
159 pthread_mutex_lock(&func_mutex); \
161 _open64 = (int (*)(const char *, int, mode_t)) dlsym_fn(RTLD_NEXT, "open64"); \
162 pthread_mutex_unlock(&func_mutex); \
165 #define LOAD_CLOSE_FUNC() \
167 pthread_mutex_lock(&func_mutex); \
169 _close = (int (*)(int)) dlsym_fn(RTLD_NEXT, "close"); \
170 pthread_mutex_unlock(&func_mutex); \
173 #define LOAD_ACCESS_FUNC() \
175 pthread_mutex_lock(&func_mutex); \
177 _access = (int (*)(const char*, int)) dlsym_fn(RTLD_NEXT, "access"); \
178 pthread_mutex_unlock(&func_mutex); \
181 #define LOAD_STAT_FUNC() \
183 pthread_mutex_lock(&func_mutex); \
185 _stat = (int (*)(const char *, struct stat *)) dlsym_fn(RTLD_NEXT, "stat"); \
186 pthread_mutex_unlock(&func_mutex); \
189 #define LOAD_STAT64_FUNC() \
191 pthread_mutex_lock(&func_mutex); \
193 _stat64 = (int (*)(const char *, struct stat64 *)) dlsym_fn(RTLD_NEXT, "stat64"); \
194 pthread_mutex_unlock(&func_mutex); \
197 #define LOAD_XSTAT_FUNC() \
199 pthread_mutex_lock(&func_mutex); \
201 ___xstat = (int (*)(int, const char *, struct stat *)) dlsym_fn(RTLD_NEXT, "__xstat"); \
202 pthread_mutex_unlock(&func_mutex); \
205 #define LOAD_XSTAT64_FUNC() \
207 pthread_mutex_lock(&func_mutex); \
209 ___xstat64 = (int (*)(int, const char *, struct stat64 *)) dlsym_fn(RTLD_NEXT, "__xstat64"); \
210 pthread_mutex_unlock(&func_mutex); \
213 #define LOAD_FOPEN_FUNC() \
215 pthread_mutex_lock(&func_mutex); \
217 _fopen = (FILE* (*)(const char *, const char*)) dlsym_fn(RTLD_NEXT, "fopen"); \
218 pthread_mutex_unlock(&func_mutex); \
221 #define LOAD_FOPEN64_FUNC() \
223 pthread_mutex_lock(&func_mutex); \
225 _fopen64 = (FILE* (*)(const char *, const char*)) dlsym_fn(RTLD_NEXT, "fopen64"); \
226 pthread_mutex_unlock(&func_mutex); \
229 #define LOAD_FCLOSE_FUNC() \
231 pthread_mutex_lock(&func_mutex); \
233 _fclose = (int (*)(FILE *)) dlsym_fn(RTLD_NEXT, "fclose"); \
234 pthread_mutex_unlock(&func_mutex); \
237 #define CONTEXT_CHECK_DEAD_GOTO(i, label) do { \
238 if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \
239 debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \
244 #define PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, label) do { \
245 if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \
246 !(i)->play_stream || pa_stream_get_state((i)->play_stream) != PA_STREAM_READY) { \
247 debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \
252 #define RECORD_STREAM_CHECK_DEAD_GOTO(i, label) do { \
253 if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \
254 !(i)->rec_stream || pa_stream_get_state((i)->rec_stream) != PA_STREAM_READY) { \
255 debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \
260 static void debug(int level
, const char *format
, ...) PA_GCC_PRINTF_ATTR(2,3);
262 #define DEBUG_LEVEL_ALWAYS 0
263 #define DEBUG_LEVEL_NORMAL 1
264 #define DEBUG_LEVEL_VERBOSE 2
266 static void debug(int level
, const char *format
, ...) {
268 const char *dlevel_s
;
271 dlevel_s
= getenv("PADSP_DEBUG");
275 dlevel
= atoi(dlevel_s
);
280 va_start(ap
, format
);
281 vfprintf(stderr
, format
, ap
);
285 static int padsp_disabled(void) {
287 static int sym_resolved
= 0;
289 /* If the current process has a symbol __padsp_disabled__ we use
290 * it to detect whether we should enable our stuff or not. A
291 * program needs to be compiled with -rdynamic for this to work!
292 * The symbol must be an int containing a three bit bitmask: bit 1
293 * -> disable /dev/dsp emulation, bit 2 -> disable /dev/sndstat
294 * emulation, bit 3 -> disable /dev/mixer emulation. Hence a value
295 * of 7 disables padsp entirely. */
297 pthread_mutex_lock(&func_mutex
);
299 sym
= (int*) dlsym(RTLD_DEFAULT
, "__padsp_disabled__");
303 pthread_mutex_unlock(&func_mutex
);
311 static int dsp_cloak_enable(void) {
312 if (padsp_disabled() & 1)
315 if (getenv("PADSP_NO_DSP"))
321 static int sndstat_cloak_enable(void) {
322 if (padsp_disabled() & 2)
325 if (getenv("PADSP_NO_SNDSTAT"))
331 static int mixer_cloak_enable(void) {
332 if (padsp_disabled() & 4)
335 if (getenv("PADSP_NO_MIXER"))
340 static pthread_key_t recursion_key
;
342 static void recursion_key_alloc(void) {
343 pthread_key_create(&recursion_key
, NULL
);
346 static int function_enter(void) {
347 /* Avoid recursive calls */
348 static pthread_once_t recursion_key_once
= PTHREAD_ONCE_INIT
;
349 pthread_once(&recursion_key_once
, recursion_key_alloc
);
351 if (pthread_getspecific(recursion_key
))
354 pthread_setspecific(recursion_key
, (void*) 1);
358 static void function_exit(void) {
359 pthread_setspecific(recursion_key
, NULL
);
362 static void fd_info_free(fd_info
*i
) {
365 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": freeing fd info (fd=%i)\n", i
->app_fd
);
370 pa_threaded_mainloop_stop(i
->mainloop
);
372 if (i
->play_stream
) {
373 pa_stream_disconnect(i
->play_stream
);
374 pa_stream_unref(i
->play_stream
);
378 pa_stream_disconnect(i
->rec_stream
);
379 pa_stream_unref(i
->rec_stream
);
383 pa_context_disconnect(i
->context
);
384 pa_context_unref(i
->context
);
388 pa_threaded_mainloop_free(i
->mainloop
);
390 if (i
->app_fd
>= 0) {
395 if (i
->thread_fd
>= 0) {
397 _close(i
->thread_fd
);
402 pthread_mutex_destroy(&i
->mutex
);
406 static fd_info
*fd_info_ref(fd_info
*i
) {
409 pthread_mutex_lock(&i
->mutex
);
413 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": ref++, now %i\n", i
->ref
);
414 pthread_mutex_unlock(&i
->mutex
);
419 static void fd_info_unref(fd_info
*i
) {
421 pthread_mutex_lock(&i
->mutex
);
424 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": ref--, now %i\n", i
->ref
);
425 pthread_mutex_unlock(&i
->mutex
);
431 static void context_state_cb(pa_context
*c
, void *userdata
) {
432 fd_info
*i
= userdata
;
435 switch (pa_context_get_state(c
)) {
436 case PA_CONTEXT_READY
:
437 case PA_CONTEXT_TERMINATED
:
438 case PA_CONTEXT_FAILED
:
439 pa_threaded_mainloop_signal(i
->mainloop
, 0);
442 case PA_CONTEXT_UNCONNECTED
:
443 case PA_CONTEXT_CONNECTING
:
444 case PA_CONTEXT_AUTHORIZING
:
445 case PA_CONTEXT_SETTING_NAME
:
450 static void reset_params(fd_info
*i
) {
453 i
->sample_spec
.format
= PA_SAMPLE_U8
;
454 i
->sample_spec
.channels
= 1;
455 i
->sample_spec
.rate
= 8000;
456 i
->fragment_size
= 0;
460 static const char *client_name(char *buf
, size_t n
) {
464 if ((e
= getenv("PADSP_CLIENT_NAME")))
467 if (pa_get_binary_name(p
, sizeof(p
)))
468 snprintf(buf
, n
, "OSS Emulation[%s]", p
);
470 snprintf(buf
, n
, "OSS");
475 static const char *stream_name(void) {
478 if ((e
= getenv("PADSP_STREAM_NAME")))
481 return "Audio Stream";
484 static void atfork_prepare(void) {
487 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_prepare() enter\n");
491 pthread_mutex_lock(&fd_infos_mutex
);
493 for (i
= fd_infos
; i
; i
= i
->next
) {
494 pthread_mutex_lock(&i
->mutex
);
495 pa_threaded_mainloop_lock(i
->mainloop
);
498 pthread_mutex_lock(&func_mutex
);
501 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_prepare() exit\n");
504 static void atfork_parent(void) {
507 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_parent() enter\n");
509 pthread_mutex_unlock(&func_mutex
);
511 for (i
= fd_infos
; i
; i
= i
->next
) {
512 pa_threaded_mainloop_unlock(i
->mainloop
);
513 pthread_mutex_unlock(&i
->mutex
);
516 pthread_mutex_unlock(&fd_infos_mutex
);
520 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_parent() exit\n");
523 static void atfork_child(void) {
526 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_child() enter\n");
528 /* We do only the bare minimum to get all fds closed */
529 pthread_mutex_init(&func_mutex
, NULL
);
530 pthread_mutex_init(&fd_infos_mutex
, NULL
);
532 for (i
= fd_infos
; i
; i
= i
->next
) {
533 pthread_mutex_init(&i
->mutex
, NULL
);
536 pa_context_disconnect(i
->context
);
537 pa_context_unref(i
->context
);
541 if (i
->play_stream
) {
542 pa_stream_unref(i
->play_stream
);
543 i
->play_stream
= NULL
;
547 pa_stream_unref(i
->rec_stream
);
548 i
->rec_stream
= NULL
;
551 if (i
->app_fd
>= 0) {
556 if (i
->thread_fd
>= 0) {
566 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_child() exit\n");
569 static void install_atfork(void) {
570 pthread_atfork(atfork_prepare
, atfork_parent
, atfork_child
);
573 static void stream_success_cb(pa_stream
*s
, int success
, void *userdata
) {
574 fd_info
*i
= userdata
;
579 i
->operation_success
= success
;
580 pa_threaded_mainloop_signal(i
->mainloop
, 0);
583 static void context_success_cb(pa_context
*c
, int success
, void *userdata
) {
584 fd_info
*i
= userdata
;
589 i
->operation_success
= success
;
590 pa_threaded_mainloop_signal(i
->mainloop
, 0);
593 static fd_info
* fd_info_new(fd_info_type_t type
, int *_errno
) {
595 int sfds
[2] = { -1, -1 };
597 static pthread_once_t install_atfork_once
= PTHREAD_ONCE_INIT
;
599 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": fd_info_new()\n");
601 signal(SIGPIPE
, SIG_IGN
); /* Yes, ugly as hell */
603 pthread_once(&install_atfork_once
, install_atfork
);
605 if (!(i
= malloc(sizeof(fd_info
)))) {
610 i
->app_fd
= i
->thread_fd
= -1;
615 i
->play_stream
= NULL
;
616 i
->rec_stream
= NULL
;
621 pthread_mutex_init(&i
->mutex
, NULL
);
626 pa_cvolume_reset(&i
->sink_volume
, 2);
627 pa_cvolume_reset(&i
->source_volume
, 2);
628 i
->volume_modify_count
= 0;
629 i
->sink_index
= (uint32_t) -1;
630 i
->source_index
= (uint32_t) -1;
631 i
->optr_n_blocks
= 0;
632 PA_LLIST_INIT(fd_info
, i
);
636 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, sfds
) < 0) {
638 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": socket() failed: %s\n", strerror(errno
));
643 i
->thread_fd
= sfds
[1];
645 if (!(i
->mainloop
= pa_threaded_mainloop_new())) {
647 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_threaded_mainloop_new() failed\n");
651 if (!(i
->context
= pa_context_new(pa_threaded_mainloop_get_api(i
->mainloop
), client_name(name
, sizeof(name
))))) {
653 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_context_new() failed\n");
657 pa_context_set_state_callback(i
->context
, context_state_cb
, i
);
659 if (pa_context_connect(i
->context
, NULL
, 0, NULL
) < 0) {
660 *_errno
= ECONNREFUSED
;
661 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
665 pa_threaded_mainloop_lock(i
->mainloop
);
667 if (pa_threaded_mainloop_start(i
->mainloop
) < 0) {
669 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_threaded_mainloop_start() failed\n");
670 goto unlock_and_fail
;
673 /* Wait until the context is ready */
674 pa_threaded_mainloop_wait(i
->mainloop
);
676 if (pa_context_get_state(i
->context
) != PA_CONTEXT_READY
) {
677 *_errno
= ECONNREFUSED
;
678 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
679 goto unlock_and_fail
;
682 pa_threaded_mainloop_unlock(i
->mainloop
);
687 pa_threaded_mainloop_unlock(i
->mainloop
);
697 static void fd_info_add_to_list(fd_info
*i
) {
700 pthread_mutex_lock(&fd_infos_mutex
);
701 PA_LLIST_PREPEND(fd_info
, fd_infos
, i
);
702 pthread_mutex_unlock(&fd_infos_mutex
);
707 static void fd_info_remove_from_list(fd_info
*i
) {
710 pthread_mutex_lock(&fd_infos_mutex
);
711 PA_LLIST_REMOVE(fd_info
, fd_infos
, i
);
712 pthread_mutex_unlock(&fd_infos_mutex
);
717 static fd_info
* fd_info_find(int fd
) {
720 pthread_mutex_lock(&fd_infos_mutex
);
722 for (i
= fd_infos
; i
; i
= i
->next
)
723 if (i
->app_fd
== fd
&& !i
->unusable
) {
728 pthread_mutex_unlock(&fd_infos_mutex
);
733 static void fix_metrics(fd_info
*i
) {
735 char t
[PA_SAMPLE_SPEC_SNPRINT_MAX
];
737 fs
= pa_frame_size(&i
->sample_spec
);
739 /* Don't fix things more than necessary */
740 if ((i
->fragment_size
% fs
) == 0 &&
741 i
->n_fragments
>= 2 &&
742 i
->fragment_size
> 0)
745 i
->fragment_size
= (i
->fragment_size
/fs
)*fs
;
747 /* Number of fragments set? */
748 if (i
->n_fragments
< 2) {
749 if (i
->fragment_size
> 0) {
750 i
->n_fragments
= pa_bytes_per_second(&i
->sample_spec
) / 2 / i
->fragment_size
;
751 if (i
->n_fragments
< 2)
757 /* Fragment size set? */
758 if (i
->fragment_size
<= 0) {
759 i
->fragment_size
= pa_bytes_per_second(&i
->sample_spec
) / 2 / i
->n_fragments
;
760 if (i
->fragment_size
< 1024)
761 i
->fragment_size
= 1024;
764 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": sample spec: %s\n", pa_sample_spec_snprint(t
, sizeof(t
), &i
->sample_spec
));
765 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": fixated metrics to %i fragments, %li bytes each.\n", i
->n_fragments
, (long)i
->fragment_size
);
768 static void stream_request_cb(pa_stream
*s
, size_t length
, void *userdata
) {
769 fd_info
*i
= userdata
;
773 pa_mainloop_api
*api
;
776 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
778 if (s
== i
->play_stream
) {
779 n
= pa_stream_writable_size(i
->play_stream
);
780 if (n
== (size_t)-1) {
781 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_writable_size(): %s\n",
782 pa_strerror(pa_context_errno(i
->context
)));
785 if (n
>= i
->fragment_size
)
786 i
->io_flags
|= PA_IO_EVENT_INPUT
;
788 i
->io_flags
&= ~PA_IO_EVENT_INPUT
;
791 if (s
== i
->rec_stream
) {
792 n
= pa_stream_readable_size(i
->rec_stream
);
793 if (n
== (size_t)-1) {
794 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_readable_size(): %s\n",
795 pa_strerror(pa_context_errno(i
->context
)));
798 if (n
>= i
->fragment_size
)
799 i
->io_flags
|= PA_IO_EVENT_OUTPUT
;
801 i
->io_flags
&= ~PA_IO_EVENT_OUTPUT
;
804 api
->io_enable(i
->io_event
, i
->io_flags
);
808 static void stream_latency_update_cb(pa_stream
*s
, void *userdata
) {
809 fd_info
*i
= userdata
;
812 pa_threaded_mainloop_signal(i
->mainloop
, 0);
815 static void fd_info_shutdown(fd_info
*i
) {
819 pa_mainloop_api
*api
;
820 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
821 api
->io_free(i
->io_event
);
826 if (i
->thread_fd
>= 0) {
832 static int fd_info_copy_data(fd_info
*i
, int force
) {
835 if (!i
->play_stream
&& !i
->rec_stream
)
838 if ((i
->play_stream
) && (pa_stream_get_state(i
->play_stream
) == PA_STREAM_READY
)) {
839 n
= pa_stream_writable_size(i
->play_stream
);
841 if (n
== (size_t)-1) {
842 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_writable_size(): %s\n",
843 pa_strerror(pa_context_errno(i
->context
)));
847 while (n
>= i
->fragment_size
|| force
) {
851 if (!(i
->buf
= malloc(i
->fragment_size
))) {
852 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": malloc() failed.\n");
857 if ((r
= read(i
->thread_fd
, i
->buf
, i
->fragment_size
)) <= 0) {
862 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": read(): %s\n", r
== 0 ? "EOF" : strerror(errno
));
866 if (pa_stream_write(i
->play_stream
, i
->buf
, r
, free
, 0, PA_SEEK_RELATIVE
) < 0) {
867 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
873 assert(n
>= (size_t) r
);
877 if (n
>= i
->fragment_size
)
878 i
->io_flags
|= PA_IO_EVENT_INPUT
;
880 i
->io_flags
&= ~PA_IO_EVENT_INPUT
;
883 if ((i
->rec_stream
) && (pa_stream_get_state(i
->rec_stream
) == PA_STREAM_READY
)) {
884 n
= pa_stream_readable_size(i
->rec_stream
);
886 if (n
== (size_t)-1) {
887 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_readable_size(): %s\n",
888 pa_strerror(pa_context_errno(i
->context
)));
892 while (n
>= i
->fragment_size
|| force
) {
898 if (pa_stream_peek(i
->rec_stream
, &data
, &len
) < 0) {
899 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_peek(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
906 buf
= (const char*)data
+ i
->rec_offset
;
908 if ((r
= write(i
->thread_fd
, buf
, len
- i
->rec_offset
)) <= 0) {
913 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": write(): %s\n", strerror(errno
));
917 assert((size_t)r
<= len
- i
->rec_offset
);
920 if (i
->rec_offset
== len
) {
921 if (pa_stream_drop(i
->rec_stream
) < 0) {
922 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_drop(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
928 assert(n
>= (size_t) r
);
932 if (n
>= i
->fragment_size
)
933 i
->io_flags
|= PA_IO_EVENT_OUTPUT
;
935 i
->io_flags
&= ~PA_IO_EVENT_OUTPUT
;
939 pa_mainloop_api
*api
;
941 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
942 api
->io_enable(i
->io_event
, i
->io_flags
);
948 static void stream_state_cb(pa_stream
*s
, void * userdata
) {
949 fd_info
*i
= userdata
;
952 switch (pa_stream_get_state(s
)) {
954 case PA_STREAM_READY
:
955 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": stream established.\n");
958 case PA_STREAM_FAILED
:
959 if (s
== i
->play_stream
) {
960 debug(DEBUG_LEVEL_NORMAL
,
961 __FILE__
": pa_stream_connect_playback() failed: %s\n",
962 pa_strerror(pa_context_errno(i
->context
)));
963 pa_stream_unref(i
->play_stream
);
964 i
->play_stream
= NULL
;
965 } else if (s
== i
->rec_stream
) {
966 debug(DEBUG_LEVEL_NORMAL
,
967 __FILE__
": pa_stream_connect_record() failed: %s\n",
968 pa_strerror(pa_context_errno(i
->context
)));
969 pa_stream_unref(i
->rec_stream
);
970 i
->rec_stream
= NULL
;
975 case PA_STREAM_TERMINATED
:
976 case PA_STREAM_UNCONNECTED
:
977 case PA_STREAM_CREATING
:
982 static int create_playback_stream(fd_info
*i
) {
990 if (!(i
->play_stream
= pa_stream_new(i
->context
, stream_name(), &i
->sample_spec
, NULL
))) {
991 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
995 pa_stream_set_state_callback(i
->play_stream
, stream_state_cb
, i
);
996 pa_stream_set_write_callback(i
->play_stream
, stream_request_cb
, i
);
997 pa_stream_set_latency_update_callback(i
->play_stream
, stream_latency_update_cb
, i
);
999 memset(&attr
, 0, sizeof(attr
));
1000 attr
.maxlength
= i
->fragment_size
* (i
->n_fragments
+1);
1001 attr
.tlength
= i
->fragment_size
* i
->n_fragments
;
1002 attr
.prebuf
= i
->fragment_size
;
1003 attr
.minreq
= i
->fragment_size
;
1005 flags
= PA_STREAM_INTERPOLATE_TIMING
|PA_STREAM_AUTO_TIMING_UPDATE
;
1006 if (i
->play_precork
) {
1007 flags
|= PA_STREAM_START_CORKED
;
1008 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": creating stream corked\n");
1010 if (pa_stream_connect_playback(i
->play_stream
, NULL
, &attr
, flags
, NULL
, NULL
) < 0) {
1011 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
1015 n
= i
->fragment_size
;
1016 setsockopt(i
->app_fd
, SOL_SOCKET
, SO_SNDBUF
, &n
, sizeof(n
));
1017 n
= i
->fragment_size
;
1018 setsockopt(i
->thread_fd
, SOL_SOCKET
, SO_RCVBUF
, &n
, sizeof(n
));
1026 static int create_record_stream(fd_info
*i
) {
1027 pa_buffer_attr attr
;
1034 if (!(i
->rec_stream
= pa_stream_new(i
->context
, stream_name(), &i
->sample_spec
, NULL
))) {
1035 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
1039 pa_stream_set_state_callback(i
->rec_stream
, stream_state_cb
, i
);
1040 pa_stream_set_read_callback(i
->rec_stream
, stream_request_cb
, i
);
1041 pa_stream_set_latency_update_callback(i
->rec_stream
, stream_latency_update_cb
, i
);
1043 memset(&attr
, 0, sizeof(attr
));
1044 attr
.maxlength
= i
->fragment_size
* (i
->n_fragments
+1);
1045 attr
.fragsize
= i
->fragment_size
;
1047 flags
= PA_STREAM_INTERPOLATE_TIMING
|PA_STREAM_AUTO_TIMING_UPDATE
;
1048 if (i
->rec_precork
) {
1049 flags
|= PA_STREAM_START_CORKED
;
1050 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": creating stream corked\n");
1052 if (pa_stream_connect_record(i
->rec_stream
, NULL
, &attr
, flags
) < 0) {
1053 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
1057 n
= i
->fragment_size
;
1058 setsockopt(i
->app_fd
, SOL_SOCKET
, SO_RCVBUF
, &n
, sizeof(n
));
1059 n
= i
->fragment_size
;
1060 setsockopt(i
->thread_fd
, SOL_SOCKET
, SO_SNDBUF
, &n
, sizeof(n
));
1068 static void free_streams(fd_info
*i
) {
1071 if (i
->play_stream
) {
1072 pa_stream_disconnect(i
->play_stream
);
1073 pa_stream_unref(i
->play_stream
);
1074 i
->play_stream
= NULL
;
1075 i
->io_flags
|= PA_IO_EVENT_INPUT
;
1078 if (i
->rec_stream
) {
1079 pa_stream_disconnect(i
->rec_stream
);
1080 pa_stream_unref(i
->rec_stream
);
1081 i
->rec_stream
= NULL
;
1082 i
->io_flags
|= PA_IO_EVENT_OUTPUT
;
1086 pa_mainloop_api
*api
;
1088 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
1089 api
->io_enable(i
->io_event
, i
->io_flags
);
1093 static void io_event_cb(pa_mainloop_api
*api
, pa_io_event
*e
, int fd
, pa_io_event_flags_t flags
, void *userdata
) {
1094 fd_info
*i
= userdata
;
1096 pa_threaded_mainloop_signal(i
->mainloop
, 0);
1098 if (flags
& PA_IO_EVENT_INPUT
) {
1100 if (!i
->play_stream
) {
1101 if (create_playback_stream(i
) < 0)
1104 if (fd_info_copy_data(i
, 0) < 0)
1108 } else if (flags
& PA_IO_EVENT_OUTPUT
) {
1110 if (!i
->rec_stream
) {
1111 if (create_record_stream(i
) < 0)
1114 if (fd_info_copy_data(i
, 0) < 0)
1118 } else if (flags
& (PA_IO_EVENT_HANGUP
|PA_IO_EVENT_ERROR
))
1124 /* We can't do anything better than removing the event source */
1125 fd_info_shutdown(i
);
1128 static int dsp_open(int flags
, int *_errno
) {
1130 pa_mainloop_api
*api
;
1134 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": dsp_open()\n");
1136 if (!(i
= fd_info_new(FD_INFO_STREAM
, _errno
)))
1139 if ((flags
& O_NONBLOCK
) == O_NONBLOCK
) {
1140 if ((f
= fcntl(i
->app_fd
, F_GETFL
)) >= 0)
1141 fcntl(i
->app_fd
, F_SETFL
, f
|O_NONBLOCK
);
1143 if ((f
= fcntl(i
->thread_fd
, F_GETFL
)) >= 0)
1144 fcntl(i
->thread_fd
, F_SETFL
, f
|O_NONBLOCK
);
1146 fcntl(i
->app_fd
, F_SETFD
, FD_CLOEXEC
);
1147 fcntl(i
->thread_fd
, F_SETFD
, FD_CLOEXEC
);
1149 pa_threaded_mainloop_lock(i
->mainloop
);
1150 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
1152 switch (flags
& O_ACCMODE
) {
1154 i
->io_flags
= PA_IO_EVENT_OUTPUT
;
1155 shutdown(i
->thread_fd
, SHUT_RD
);
1156 shutdown(i
->app_fd
, SHUT_WR
);
1159 i
->io_flags
= PA_IO_EVENT_INPUT
;
1160 shutdown(i
->thread_fd
, SHUT_WR
);
1161 shutdown(i
->app_fd
, SHUT_RD
);
1164 i
->io_flags
= PA_IO_EVENT_INPUT
| PA_IO_EVENT_OUTPUT
;
1170 if (!(i
->io_event
= api
->io_new(api
, i
->thread_fd
, i
->io_flags
, io_event_cb
, i
)))
1173 pa_threaded_mainloop_unlock(i
->mainloop
);
1175 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": dsp_open() succeeded, fd=%i\n", i
->app_fd
);
1177 fd_info_add_to_list(i
);
1184 pa_threaded_mainloop_unlock(i
->mainloop
);
1191 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": dsp_open() failed\n");
1196 static void sink_info_cb(pa_context
*context
, const pa_sink_info
*si
, int eol
, void *userdata
) {
1197 fd_info
*i
= userdata
;
1199 if (!si
&& eol
< 0) {
1200 i
->operation_success
= 0;
1201 pa_threaded_mainloop_signal(i
->mainloop
, 0);
1208 if (!pa_cvolume_equal(&i
->sink_volume
, &si
->volume
))
1209 i
->volume_modify_count
++;
1211 i
->sink_volume
= si
->volume
;
1212 i
->sink_index
= si
->index
;
1214 i
->operation_success
= 1;
1215 pa_threaded_mainloop_signal(i
->mainloop
, 0);
1218 static void source_info_cb(pa_context
*context
, const pa_source_info
*si
, int eol
, void *userdata
) {
1219 fd_info
*i
= userdata
;
1221 if (!si
&& eol
< 0) {
1222 i
->operation_success
= 0;
1223 pa_threaded_mainloop_signal(i
->mainloop
, 0);
1230 if (!pa_cvolume_equal(&i
->source_volume
, &si
->volume
))
1231 i
->volume_modify_count
++;
1233 i
->source_volume
= si
->volume
;
1234 i
->source_index
= si
->index
;
1236 i
->operation_success
= 1;
1237 pa_threaded_mainloop_signal(i
->mainloop
, 0);
1240 static void subscribe_cb(pa_context
*context
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1241 fd_info
*i
= userdata
;
1242 pa_operation
*o
= NULL
;
1244 if (i
->sink_index
!= idx
)
1247 if ((t
& PA_SUBSCRIPTION_EVENT_TYPE_MASK
) != PA_SUBSCRIPTION_EVENT_CHANGE
)
1250 if (!(o
= pa_context_get_sink_info_by_index(i
->context
, i
->sink_index
, sink_info_cb
, i
))) {
1251 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to get sink info: %s", pa_strerror(pa_context_errno(i
->context
)));
1255 pa_operation_unref(o
);
1258 static int mixer_open(int flags
, int *_errno
) {
1260 pa_operation
*o
= NULL
;
1263 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": mixer_open()\n");
1265 if (!(i
= fd_info_new(FD_INFO_MIXER
, _errno
)))
1268 pa_threaded_mainloop_lock(i
->mainloop
);
1270 pa_context_set_subscribe_callback(i
->context
, subscribe_cb
, i
);
1272 if (!(o
= pa_context_subscribe(i
->context
, PA_SUBSCRIPTION_MASK_SINK
| PA_SUBSCRIPTION_MASK_SOURCE
, context_success_cb
, i
))) {
1273 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i
->context
)));
1278 i
->operation_success
= 0;
1279 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1280 pa_threaded_mainloop_wait(i
->mainloop
);
1281 CONTEXT_CHECK_DEAD_GOTO(i
, fail
);
1284 pa_operation_unref(o
);
1287 if (!i
->operation_success
) {
1288 debug(DEBUG_LEVEL_NORMAL
, __FILE__
":Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i
->context
)));
1295 if (!(o
= pa_context_get_sink_info_by_name(i
->context
, NULL
, sink_info_cb
, i
))) {
1296 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to get sink info: %s", pa_strerror(pa_context_errno(i
->context
)));
1301 i
->operation_success
= 0;
1302 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1303 pa_threaded_mainloop_wait(i
->mainloop
);
1304 CONTEXT_CHECK_DEAD_GOTO(i
, fail
);
1307 pa_operation_unref(o
);
1310 if (!i
->operation_success
) {
1311 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to get sink info: %s", pa_strerror(pa_context_errno(i
->context
)));
1316 /* Get source info */
1318 if (!(o
= pa_context_get_source_info_by_name(i
->context
, NULL
, source_info_cb
, i
))) {
1319 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to get source info: %s", pa_strerror(pa_context_errno(i
->context
)));
1324 i
->operation_success
= 0;
1325 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1326 pa_threaded_mainloop_wait(i
->mainloop
);
1327 CONTEXT_CHECK_DEAD_GOTO(i
, fail
);
1330 pa_operation_unref(o
);
1333 if (!i
->operation_success
) {
1334 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to get source info: %s", pa_strerror(pa_context_errno(i
->context
)));
1339 pa_threaded_mainloop_unlock(i
->mainloop
);
1341 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": mixer_open() succeeded, fd=%i\n", i
->app_fd
);
1343 fd_info_add_to_list(i
);
1351 pa_operation_unref(o
);
1353 pa_threaded_mainloop_unlock(i
->mainloop
);
1360 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": mixer_open() failed\n");
1365 static int sndstat_open(int flags
, int *_errno
) {
1366 static const char sndstat
[] =
1367 "Sound Driver:3.8.1a-980706 (PulseAudio Virtual OSS)\n"
1369 "Config options: 0\n"
1371 "Installed drivers:\n"
1372 "Type 255: PulseAudio Virtual OSS\n"
1375 "PulseAudio Virtual OSS\n"
1378 "0: PulseAudio Virtual OSS\n"
1380 "Synth devices: NOT ENABLED IN CONFIG\n"
1387 "0: PulseAudio Virtual OSS\n";
1389 char fn
[] = "/tmp/padsp-sndstat-XXXXXX";
1394 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": sndstat_open()\n");
1396 if (flags
!= O_RDONLY
1398 && flags
!= (O_RDONLY
|O_LARGEFILE
)
1402 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": bad access!\n");
1413 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": mkstemp() failed: %s\n", strerror(errno
));
1419 if (write(fd
, sndstat
, sizeof(sndstat
) -1) != sizeof(sndstat
)-1) {
1421 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": write() failed: %s\n", strerror(errno
));
1425 if (lseek(fd
, SEEK_SET
, 0) < 0) {
1427 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": lseek() failed: %s\n", strerror(errno
));
1439 int open(const char *filename
, int flags
, ...) {
1444 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": open(%s)\n", filename
);
1446 va_start(args
, flags
);
1447 if (flags
& O_CREAT
) {
1448 if (sizeof(mode_t
) < sizeof(int))
1449 mode
= va_arg(args
, int);
1451 mode
= va_arg(args
, mode_t
);
1455 if (!function_enter()) {
1457 return _open(filename
, flags
, mode
);
1460 if (dsp_cloak_enable() && (strcmp(filename
, "/dev/dsp") == 0 || strcmp(filename
, "/dev/adsp") == 0)) {
1461 r
= dsp_open(flags
, &_errno
);
1462 } else if (mixer_cloak_enable() && strcmp(filename
, "/dev/mixer") == 0) {
1463 r
= mixer_open(flags
, &_errno
);
1464 } else if (sndstat_cloak_enable() && strcmp(filename
, "/dev/sndstat") == 0) {
1465 r
= sndstat_open(flags
, &_errno
);
1469 return _open(filename
, flags
, mode
);
1480 static int mixer_ioctl(fd_info
*i
, unsigned long request
, void*argp
, int *_errno
) {
1484 case SOUND_MIXER_READ_DEVMASK
:
1485 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_DEVMASK\n");
1487 *(int*) argp
= SOUND_MASK_PCM
| SOUND_MASK_IGAIN
;
1490 case SOUND_MIXER_READ_RECMASK
:
1491 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_RECMASK\n");
1493 *(int*) argp
= SOUND_MASK_IGAIN
;
1496 case SOUND_MIXER_READ_STEREODEVS
:
1497 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_STEREODEVS\n");
1499 pa_threaded_mainloop_lock(i
->mainloop
);
1501 if (i
->sink_volume
.channels
> 1)
1502 *(int*) argp
|= SOUND_MASK_PCM
;
1503 if (i
->source_volume
.channels
> 1)
1504 *(int*) argp
|= SOUND_MASK_IGAIN
;
1505 pa_threaded_mainloop_unlock(i
->mainloop
);
1509 case SOUND_MIXER_READ_RECSRC
:
1510 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_RECSRC\n");
1512 *(int*) argp
= SOUND_MASK_IGAIN
;
1515 case SOUND_MIXER_WRITE_RECSRC
:
1516 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_WRITE_RECSRC\n");
1519 case SOUND_MIXER_READ_CAPS
:
1520 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_CAPS\n");
1525 case SOUND_MIXER_READ_PCM
:
1526 case SOUND_MIXER_READ_IGAIN
: {
1529 if (request
== SOUND_MIXER_READ_PCM
)
1530 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_PCM\n");
1532 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_IGAIN\n");
1534 pa_threaded_mainloop_lock(i
->mainloop
);
1536 if (request
== SOUND_MIXER_READ_PCM
)
1537 v
= &i
->sink_volume
;
1539 v
= &i
->source_volume
;
1542 ((v
->values
[0]*100/PA_VOLUME_NORM
)) |
1543 ((v
->values
[v
->channels
> 1 ? 1 : 0]*100/PA_VOLUME_NORM
) << 8);
1545 pa_threaded_mainloop_unlock(i
->mainloop
);
1550 case SOUND_MIXER_WRITE_PCM
:
1551 case SOUND_MIXER_WRITE_IGAIN
: {
1554 if (request
== SOUND_MIXER_WRITE_PCM
)
1555 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_WRITE_PCM\n");
1557 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_WRITE_IGAIN\n");
1559 pa_threaded_mainloop_lock(i
->mainloop
);
1561 if (request
== SOUND_MIXER_WRITE_PCM
) {
1563 pv
= &i
->sink_volume
;
1565 v
= i
->source_volume
;
1566 pv
= &i
->source_volume
;
1569 pv
->values
[0] = ((*(int*) argp
& 0xFF)*PA_VOLUME_NORM
)/100;
1570 pv
->values
[1] = ((*(int*) argp
>> 8)*PA_VOLUME_NORM
)/100;
1572 if (!pa_cvolume_equal(pv
, &v
)) {
1575 if (request
== SOUND_MIXER_WRITE_PCM
)
1576 o
= pa_context_set_sink_volume_by_index(i
->context
, i
->sink_index
, pv
, context_success_cb
, i
);
1578 o
= pa_context_set_source_volume_by_index(i
->context
, i
->source_index
, pv
, context_success_cb
, i
);
1581 debug(DEBUG_LEVEL_NORMAL
, __FILE__
":Failed set volume: %s", pa_strerror(pa_context_errno(i
->context
)));
1584 i
->operation_success
= 0;
1585 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1586 CONTEXT_CHECK_DEAD_GOTO(i
, exit_loop
);
1588 pa_threaded_mainloop_wait(i
->mainloop
);
1592 if (!i
->operation_success
)
1593 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to set volume: %s\n", pa_strerror(pa_context_errno(i
->context
)));
1595 pa_operation_unref(o
);
1598 /* We don't wait for completion here */
1599 i
->volume_modify_count
++;
1602 pa_threaded_mainloop_unlock(i
->mainloop
);
1607 case SOUND_MIXER_INFO
: {
1608 mixer_info
*mi
= argp
;
1610 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_INFO\n");
1612 memset(mi
, 0, sizeof(mixer_info
));
1613 strncpy(mi
->id
, "PULSEAUDIO", sizeof(mi
->id
));
1614 strncpy(mi
->name
, "PulseAudio Virtual OSS", sizeof(mi
->name
));
1615 pa_threaded_mainloop_lock(i
->mainloop
);
1616 mi
->modify_counter
= i
->volume_modify_count
;
1617 pa_threaded_mainloop_unlock(i
->mainloop
);
1622 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": unknown ioctl 0x%08lx\n", request
);
1635 static int map_format(int *fmt
, pa_sample_spec
*ss
) {
1639 ss
->format
= PA_SAMPLE_ULAW
;
1643 ss
->format
= PA_SAMPLE_ALAW
;
1650 ss
->format
= PA_SAMPLE_U8
;
1657 ss
->format
= PA_SAMPLE_S16BE
;
1664 ss
->format
= PA_SAMPLE_S16LE
;
1668 ss
->format
= PA_SAMPLE_S16NE
;
1676 static int map_format_back(pa_sample_format_t format
) {
1678 case PA_SAMPLE_S16LE
: return AFMT_S16_LE
;
1679 case PA_SAMPLE_S16BE
: return AFMT_S16_BE
;
1680 case PA_SAMPLE_ULAW
: return AFMT_MU_LAW
;
1681 case PA_SAMPLE_ALAW
: return AFMT_A_LAW
;
1682 case PA_SAMPLE_U8
: return AFMT_U8
;
1688 static int dsp_flush_fd(int fd
) {
1692 if (ioctl(fd
, SIOCINQ
, &l
) < 0) {
1693 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SIOCINQ: %s\n", strerror(errno
));
1701 k
= (size_t) l
> sizeof(buf
) ? sizeof(buf
) : (size_t) l
;
1702 if (read(fd
, buf
, k
) < 0)
1703 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": read(): %s\n", strerror(errno
));
1709 # warning "Your platform does not support SIOCINQ, something might not work as intended."
1714 static int dsp_flush_socket(fd_info
*i
) {
1717 if ((i
->thread_fd
< 0) && (i
->app_fd
< 0))
1720 if (i
->thread_fd
>= 0)
1721 res
= dsp_flush_fd(i
->thread_fd
);
1727 res
= dsp_flush_fd(i
->app_fd
);
1735 static int dsp_empty_socket(fd_info
*i
) {
1739 /* Empty the socket */
1743 if (i
->thread_fd
< 0)
1746 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0) {
1747 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SIOCINQ: %s\n", strerror(errno
));
1756 pa_threaded_mainloop_wait(i
->mainloop
);
1761 # warning "Your platform does not support SIOCINQ, something might not work as intended."
1766 static int dsp_drain(fd_info
*i
) {
1767 pa_operation
*o
= NULL
;
1773 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Draining.\n");
1775 pa_threaded_mainloop_lock(i
->mainloop
);
1777 if (dsp_empty_socket(i
) < 0)
1780 if (!i
->play_stream
)
1783 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Really draining.\n");
1785 if (!(o
= pa_stream_drain(i
->play_stream
, stream_success_cb
, i
))) {
1786 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1790 i
->operation_success
= 0;
1791 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1792 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i
, fail
);
1794 pa_threaded_mainloop_wait(i
->mainloop
);
1797 if (!i
->operation_success
) {
1798 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i
->context
)));
1807 pa_operation_unref(o
);
1809 pa_threaded_mainloop_unlock(i
->mainloop
);
1814 static int dsp_trigger(fd_info
*i
) {
1815 pa_operation
*o
= NULL
;
1818 if (!i
->play_stream
)
1821 pa_threaded_mainloop_lock(i
->mainloop
);
1823 if (dsp_empty_socket(i
) < 0)
1826 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Triggering.\n");
1828 if (!(o
= pa_stream_trigger(i
->play_stream
, stream_success_cb
, i
))) {
1829 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1833 i
->operation_success
= 0;
1834 while (!pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1835 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i
, fail
);
1837 pa_threaded_mainloop_wait(i
->mainloop
);
1840 if (!i
->operation_success
) {
1841 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1850 pa_operation_unref(o
);
1852 pa_threaded_mainloop_unlock(i
->mainloop
);
1857 static int dsp_cork(fd_info
*i
, pa_stream
*s
, int b
) {
1858 pa_operation
*o
= NULL
;
1861 pa_threaded_mainloop_lock(i
->mainloop
);
1863 if (!(o
= pa_stream_cork(s
, b
, stream_success_cb
, i
))) {
1864 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_cork(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1868 i
->operation_success
= 0;
1869 while (!pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1870 if (s
== i
->play_stream
)
1871 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i
, fail
);
1872 else if (s
== i
->rec_stream
)
1873 RECORD_STREAM_CHECK_DEAD_GOTO(i
, fail
);
1875 pa_threaded_mainloop_wait(i
->mainloop
);
1878 if (!i
->operation_success
) {
1879 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_cork(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1888 pa_operation_unref(o
);
1890 pa_threaded_mainloop_unlock(i
->mainloop
);
1895 static int dsp_ioctl(fd_info
*i
, unsigned long request
, void*argp
, int *_errno
) {
1898 if (i
->thread_fd
== -1) {
1900 * We've encountered some fatal error and are just waiting
1903 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": got ioctl 0x%08lx in fatal error state\n", request
);
1909 case SNDCTL_DSP_SETFMT
: {
1910 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp
);
1912 pa_threaded_mainloop_lock(i
->mainloop
);
1914 if (*(int*) argp
== AFMT_QUERY
)
1915 *(int*) argp
= map_format_back(i
->sample_spec
.format
);
1917 map_format((int*) argp
, &i
->sample_spec
);
1921 pa_threaded_mainloop_unlock(i
->mainloop
);
1925 case SNDCTL_DSP_SPEED
: {
1930 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SPEED: %i\n", *(int*) argp
);
1932 pa_threaded_mainloop_lock(i
->mainloop
);
1934 ss
= i
->sample_spec
;
1935 ss
.rate
= *(int*) argp
;
1937 if ((valid
= pa_sample_spec_valid(&ss
))) {
1938 i
->sample_spec
= ss
;
1942 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": ss: %s\n", pa_sample_spec_snprint(t
, sizeof(t
), &i
->sample_spec
));
1944 pa_threaded_mainloop_unlock(i
->mainloop
);
1954 case SNDCTL_DSP_STEREO
:
1955 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_STEREO: %i\n", *(int*) argp
);
1957 pa_threaded_mainloop_lock(i
->mainloop
);
1959 i
->sample_spec
.channels
= *(int*) argp
? 2 : 1;
1962 pa_threaded_mainloop_unlock(i
->mainloop
);
1965 case SNDCTL_DSP_CHANNELS
: {
1969 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp
);
1971 pa_threaded_mainloop_lock(i
->mainloop
);
1973 ss
= i
->sample_spec
;
1974 ss
.channels
= *(int*) argp
;
1976 if ((valid
= pa_sample_spec_valid(&ss
))) {
1977 i
->sample_spec
= ss
;
1981 pa_threaded_mainloop_unlock(i
->mainloop
);
1991 case SNDCTL_DSP_GETBLKSIZE
:
1992 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETBLKSIZE\n");
1994 pa_threaded_mainloop_lock(i
->mainloop
);
1997 *(int*) argp
= i
->fragment_size
;
1999 pa_threaded_mainloop_unlock(i
->mainloop
);
2003 case SNDCTL_DSP_SETFRAGMENT
:
2004 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SETFRAGMENT: 0x%08x\n", *(int*) argp
);
2006 pa_threaded_mainloop_lock(i
->mainloop
);
2008 i
->fragment_size
= 1 << ((*(int*) argp
) & 31);
2009 i
->n_fragments
= (*(int*) argp
) >> 16;
2011 /* 0x7FFF means that we can set whatever we like */
2012 if (i
->n_fragments
== 0x7FFF)
2013 i
->n_fragments
= 12;
2017 pa_threaded_mainloop_unlock(i
->mainloop
);
2021 case SNDCTL_DSP_GETCAPS
:
2022 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_CAPS\n");
2024 *(int*) argp
= DSP_CAP_DUPLEX
| DSP_CAP_TRIGGER
2025 #ifdef DSP_CAP_MULTI
2031 case SNDCTL_DSP_GETODELAY
: {
2034 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETODELAY\n");
2036 pa_threaded_mainloop_lock(i
->mainloop
);
2043 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i
, exit_loop
);
2045 if (pa_stream_get_latency(i
->play_stream
, &usec
, NULL
) >= 0) {
2046 *(int*) argp
= pa_usec_to_bytes(usec
, &i
->sample_spec
);
2050 if (pa_context_errno(i
->context
) != PA_ERR_NODATA
) {
2051 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
2055 pa_threaded_mainloop_wait(i
->mainloop
);
2061 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0)
2062 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SIOCINQ failed: %s\n", strerror(errno
));
2066 # warning "Your platform does not support SIOCINQ, something might not work as intended."
2069 pa_threaded_mainloop_unlock(i
->mainloop
);
2071 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": ODELAY: %i\n", *(int*) argp
);
2076 case SNDCTL_DSP_RESET
: {
2077 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_RESET\n");
2079 pa_threaded_mainloop_lock(i
->mainloop
);
2082 dsp_flush_socket(i
);
2084 i
->optr_n_blocks
= 0;
2086 pa_threaded_mainloop_unlock(i
->mainloop
);
2090 case SNDCTL_DSP_GETFMTS
: {
2091 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETFMTS\n");
2093 *(int*) argp
= AFMT_MU_LAW
|AFMT_A_LAW
|AFMT_U8
|AFMT_S16_LE
|AFMT_S16_BE
;
2097 case SNDCTL_DSP_POST
:
2098 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_POST\n");
2100 if (dsp_trigger(i
) < 0)
2104 case SNDCTL_DSP_GETTRIGGER
:
2105 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETTRIGGER\n");
2108 if (!i
->play_precork
)
2109 *(int*) argp
|= PCM_ENABLE_OUTPUT
;
2110 if (!i
->rec_precork
)
2111 *(int*) argp
|= PCM_ENABLE_INPUT
;
2115 case SNDCTL_DSP_SETTRIGGER
:
2116 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SETTRIGGER: 0x%08x\n", *(int*) argp
);
2123 i
->play_precork
= !((*(int*) argp
) & PCM_ENABLE_OUTPUT
);
2125 if (i
->play_stream
) {
2126 if (dsp_cork(i
, i
->play_stream
, !((*(int*) argp
) & PCM_ENABLE_OUTPUT
)) < 0)
2128 if (dsp_trigger(i
) < 0)
2132 i
->rec_precork
= !((*(int*) argp
) & PCM_ENABLE_INPUT
);
2134 if (i
->rec_stream
) {
2135 if (dsp_cork(i
, i
->rec_stream
, !((*(int*) argp
) & PCM_ENABLE_INPUT
)) < 0)
2141 case SNDCTL_DSP_SYNC
:
2142 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SYNC\n");
2144 if (dsp_drain(i
) < 0)
2149 case SNDCTL_DSP_GETOSPACE
:
2150 case SNDCTL_DSP_GETISPACE
: {
2151 audio_buf_info
*bi
= (audio_buf_info
*) argp
;
2155 if (request
== SNDCTL_DSP_GETOSPACE
)
2156 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETOSPACE\n");
2158 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETISPACE\n");
2160 pa_threaded_mainloop_lock(i
->mainloop
);
2164 if (request
== SNDCTL_DSP_GETOSPACE
) {
2165 if (i
->play_stream
) {
2166 if ((k
= pa_stream_writable_size(i
->play_stream
)) == (size_t) -1)
2167 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
2169 k
= i
->fragment_size
* i
->n_fragments
;
2172 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0) {
2173 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SIOCINQ failed: %s\n", strerror(errno
));
2177 # warning "Your platform does not dsp_flush_fd, something might not work as intended."
2180 bi
->bytes
= k
> (size_t) l
? k
- l
: 0;
2182 if (i
->rec_stream
) {
2183 if ((k
= pa_stream_readable_size(i
->rec_stream
)) == (size_t) -1)
2184 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_readable_size(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
2189 if (ioctl(i
->app_fd
, SIOCINQ
, &l
) < 0) {
2190 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SIOCINQ failed: %s\n", strerror(errno
));
2194 # warning "Your platform does not dsp_flush_fd, something might not work as intended."
2199 bi
->fragsize
= i
->fragment_size
;
2200 bi
->fragstotal
= i
->n_fragments
;
2201 bi
->fragments
= bi
->bytes
/ bi
->fragsize
;
2203 pa_threaded_mainloop_unlock(i
->mainloop
);
2205 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi
->fragsize
, bi
->fragstotal
, bi
->bytes
, bi
->fragments
);
2210 case SOUND_PCM_READ_RATE
:
2211 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_PCM_READ_RATE\n");
2213 pa_threaded_mainloop_lock(i
->mainloop
);
2214 *(int*) argp
= i
->sample_spec
.rate
;
2215 pa_threaded_mainloop_unlock(i
->mainloop
);
2218 case SOUND_PCM_READ_CHANNELS
:
2219 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_PCM_READ_CHANNELS\n");
2221 pa_threaded_mainloop_lock(i
->mainloop
);
2222 *(int*) argp
= i
->sample_spec
.channels
;
2223 pa_threaded_mainloop_unlock(i
->mainloop
);
2226 case SOUND_PCM_READ_BITS
:
2227 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_PCM_READ_BITS\n");
2229 pa_threaded_mainloop_lock(i
->mainloop
);
2230 *(int*) argp
= pa_sample_size(&i
->sample_spec
)*8;
2231 pa_threaded_mainloop_unlock(i
->mainloop
);
2234 case SNDCTL_DSP_GETOPTR
: {
2237 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETOPTR\n");
2239 info
= (count_info
*) argp
;
2240 memset(info
, 0, sizeof(*info
));
2242 pa_threaded_mainloop_lock(i
->mainloop
);
2247 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i
, exit_loop
);
2249 if (pa_stream_get_time(i
->play_stream
, &usec
) >= 0) {
2250 size_t k
= pa_usec_to_bytes(usec
, &i
->sample_spec
);
2253 info
->bytes
= (int) k
;
2254 m
= k
/ i
->fragment_size
;
2255 info
->blocks
= m
- i
->optr_n_blocks
;
2256 i
->optr_n_blocks
= m
;
2261 if (pa_context_errno(i
->context
) != PA_ERR_NODATA
) {
2262 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
2266 pa_threaded_mainloop_wait(i
->mainloop
);
2269 pa_threaded_mainloop_unlock(i
->mainloop
);
2271 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": GETOPTR bytes=%i, blocks=%i, ptr=%i\n", info
->bytes
, info
->blocks
, info
->ptr
);
2276 case SNDCTL_DSP_GETIPTR
:
2277 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": invalid ioctl SNDCTL_DSP_GETIPTR\n");
2280 case SNDCTL_DSP_SETDUPLEX
:
2281 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SETDUPLEX\n");
2282 /* this is a no-op */
2286 /* Mixer ioctls are valid on /dev/dsp aswell */
2287 return mixer_ioctl(i
, request
, argp
, _errno
);
2301 int ioctl(int fd
, unsigned long request
, ...) {
2307 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": ioctl()\n");
2309 va_start(args
, request
);
2310 argp
= va_arg(args
, void *);
2313 if (!function_enter()) {
2315 return _ioctl(fd
, request
, argp
);
2318 if (!(i
= fd_info_find(fd
))) {
2321 return _ioctl(fd
, request
, argp
);
2324 if (i
->type
== FD_INFO_MIXER
)
2325 r
= mixer_ioctl(i
, request
, argp
, &_errno
);
2327 r
= dsp_ioctl(i
, request
, argp
, &_errno
);
2342 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": close()\n");
2344 if (!function_enter()) {
2349 if (!(i
= fd_info_find(fd
))) {
2355 fd_info_remove_from_list(i
);
2363 int access(const char *pathname
, int mode
) {
2366 /* Firefox needs this. See #27 */
2371 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": access(%s)\n", pathname
);
2373 if (strcmp(pathname
, "/dev/dsp") != 0 &&
2374 strcmp(pathname
, "/dev/adsp") != 0 &&
2375 strcmp(pathname
, "/dev/sndstat") != 0 &&
2376 strcmp(pathname
, "/dev/mixer") != 0) {
2378 return _access(pathname
, mode
);
2381 if (mode
& (W_OK
| X_OK
)) {
2382 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": access(%s, %x) = EACCESS\n", pathname
, mode
);
2387 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": access(%s, %x) = OK\n", pathname
, mode
);
2392 int stat(const char *pathname
, struct stat
*buf
) {
2394 struct stat64 parent
;
2400 if (!pathname
|| !buf
) {
2405 if (strcmp(pathname
, "/dev/dsp") != 0 &&
2406 strcmp(pathname
, "/dev/adsp") != 0 &&
2407 strcmp(pathname
, "/dev/sndstat") != 0 &&
2408 strcmp(pathname
, "/dev/mixer") != 0) {
2409 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": stat(%s)\n", pathname
);
2411 return _stat(pathname
, buf
);
2414 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": stat(%s)\n", pathname
);
2418 ret
= __xstat64(_STAT_VER
, "/dev", &parent
);
2420 ret
= __xstat(_STAT_VER
, "/dev", &parent
);
2424 ret
= stat64("/dev", &parent
);
2426 ret
= stat("/dev", &parent
);
2431 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": unable to stat \"/dev\"\n");
2435 buf
->st_dev
= parent
.st_dev
;
2436 buf
->st_ino
= 0xDEADBEEF; /* FIXME: Can we do this in a safe way? */
2437 buf
->st_mode
= S_IFCHR
| S_IRUSR
| S_IWUSR
;
2439 buf
->st_uid
= getuid();
2440 buf
->st_gid
= getgid();
2441 buf
->st_rdev
= 0x0E03; /* FIXME: Linux specific */
2443 buf
->st_atime
= 1181557705;
2444 buf
->st_mtime
= 1181557705;
2445 buf
->st_ctime
= 1181557705;
2446 buf
->st_blksize
= 1;
2454 int stat64(const char *pathname
, struct stat64
*buf
) {
2458 if (!pathname
|| !buf
) {
2463 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": stat64(%s)\n", pathname
);
2465 if (strcmp(pathname
, "/dev/dsp") != 0 &&
2466 strcmp(pathname
, "/dev/adsp") != 0 &&
2467 strcmp(pathname
, "/dev/sndstat") != 0 &&
2468 strcmp(pathname
, "/dev/mixer") != 0) {
2470 return _stat64(pathname
, buf
);
2473 ret
= stat(pathname
, &oldbuf
);
2477 buf
->st_dev
= oldbuf
.st_dev
;
2478 buf
->st_ino
= oldbuf
.st_ino
;
2479 buf
->st_mode
= oldbuf
.st_mode
;
2480 buf
->st_nlink
= oldbuf
.st_nlink
;
2481 buf
->st_uid
= oldbuf
.st_uid
;
2482 buf
->st_gid
= oldbuf
.st_gid
;
2483 buf
->st_rdev
= oldbuf
.st_rdev
;
2484 buf
->st_size
= oldbuf
.st_size
;
2485 buf
->st_atime
= oldbuf
.st_atime
;
2486 buf
->st_mtime
= oldbuf
.st_mtime
;
2487 buf
->st_ctime
= oldbuf
.st_ctime
;
2488 buf
->st_blksize
= oldbuf
.st_blksize
;
2489 buf
->st_blocks
= oldbuf
.st_blocks
;
2494 int open64(const char *filename
, int flags
, ...) {
2498 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": open64(%s)\n", filename
);
2500 va_start(args
, flags
);
2501 if (flags
& O_CREAT
)
2502 mode
= va_arg(args
, mode_t
);
2505 if (strcmp(filename
, "/dev/dsp") != 0 &&
2506 strcmp(filename
, "/dev/adsp") != 0 &&
2507 strcmp(filename
, "/dev/sndstat") != 0 &&
2508 strcmp(filename
, "/dev/mixer") != 0) {
2510 return _open64(filename
, flags
, mode
);
2513 return open(filename
, flags
, mode
);
2520 int __xstat(int ver
, const char *pathname
, struct stat
*buf
) {
2521 if (!pathname
|| !buf
) {
2526 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": __xstat(%s)\n", pathname
);
2528 if (strcmp(pathname
, "/dev/dsp") != 0 &&
2529 strcmp(pathname
, "/dev/adsp") != 0 &&
2530 strcmp(pathname
, "/dev/sndstat") != 0 &&
2531 strcmp(pathname
, "/dev/mixer") != 0) {
2533 return ___xstat(ver
, pathname
, buf
);
2536 if (ver
!= _STAT_VER
) {
2541 return stat(pathname
, buf
);
2546 int __xstat64(int ver
, const char *pathname
, struct stat64
*buf
) {
2547 if (!pathname
|| !buf
) {
2552 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": __xstat64(%s)\n", pathname
);
2554 if (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
);
2581 if (strcmp(filename
, "/dev/dsp") != 0 &&
2582 strcmp(filename
, "/dev/adsp") != 0 &&
2583 strcmp(filename
, "/dev/sndstat") != 0 &&
2584 strcmp(filename
, "/dev/mixer") != 0) {
2586 return _fopen(filename
, mode
);
2602 if ((((mode
[1] == 'b') || (mode
[1] == 't')) && (mode
[2] == '+')) || (mode
[1] == '+'))
2605 if ((fd
= open(filename
, m
)) < 0)
2608 if (!(f
= fdopen(fd
, mode
))) {
2618 FILE *fopen64(const char *filename
, const char *mode
) {
2620 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": fopen64(%s)\n", filename
);
2622 if (strcmp(filename
, "/dev/dsp") != 0 &&
2623 strcmp(filename
, "/dev/adsp") != 0 &&
2624 strcmp(filename
, "/dev/sndstat") != 0 &&
2625 strcmp(filename
, "/dev/mixer") != 0) {
2626 LOAD_FOPEN64_FUNC();
2627 return _fopen64(filename
, mode
);
2630 return fopen(filename
, mode
);
2635 int fclose(FILE *f
) {
2638 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": fclose()\n");
2640 if (!function_enter()) {
2645 if (!(i
= fd_info_find(fileno(f
)))) {
2651 fd_info_remove_from_list(i
);
2653 /* Dirty trick to avoid that the fd is not freed twice, once by us
2654 * and once by the real fclose() */