4 This file is part of polypaudio.
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
11 polypaudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 #ifdef _FILE_OFFSET_BITS
27 #undef _FILE_OFFSET_BITS
30 #ifndef _LARGEFILE64_SOURCE
31 #define _LARGEFILE64_SOURCE 1
34 #include <sys/soundcard.h>
35 #include <sys/ioctl.h>
38 #include <sys/socket.h>
47 #include <linux/sockios.h>
49 #include <polyp/polypaudio.h>
50 #include <polypcore/llist.h>
51 #include <polypcore/gccmacro.h>
58 typedef struct fd_info fd_info
;
61 pthread_mutex_t mutex
;
66 int app_fd
, thread_fd
;
68 pa_sample_spec sample_spec
;
72 pa_threaded_mainloop
*mainloop
;
76 pa_io_event
*io_event
;
80 int operation_success
;
82 PA_LLIST_FIELDS(fd_info
);
85 static int dsp_drain(fd_info
*i
);
86 static void fd_info_remove_from_list(fd_info
*i
);
88 static pthread_mutex_t fd_infos_mutex
= PTHREAD_MUTEX_INITIALIZER
;
89 static pthread_mutex_t func_mutex
= PTHREAD_MUTEX_INITIALIZER
;
91 static PA_LLIST_HEAD(fd_info
, fd_infos
) = NULL
;
93 static int (*_ioctl
)(int, int, void*) = NULL
;
94 static int (*_close
)(int) = NULL
;
95 static int (*_open
)(const char *, int, mode_t
) = NULL
;
96 static FILE* (*_fopen
)(const char *path
, const char *mode
) = NULL
;
97 static int (*_open64
)(const char *, int, mode_t
) = NULL
;
98 static FILE* (*_fopen64
)(const char *path
, const char *mode
) = NULL
;
99 static int (*_fclose
)(FILE *f
) = NULL
;
101 #define LOAD_IOCTL_FUNC() \
103 pthread_mutex_lock(&func_mutex); \
105 _ioctl = (int (*)(int, int, void*)) dlsym(RTLD_NEXT, "ioctl"); \
106 pthread_mutex_unlock(&func_mutex); \
109 #define LOAD_OPEN_FUNC() \
111 pthread_mutex_lock(&func_mutex); \
113 _open = (int (*)(const char *, int, mode_t)) dlsym(RTLD_NEXT, "open"); \
114 pthread_mutex_unlock(&func_mutex); \
117 #define LOAD_OPEN64_FUNC() \
119 pthread_mutex_lock(&func_mutex); \
121 _open64 = (int (*)(const char *, int, mode_t)) dlsym(RTLD_NEXT, "open64"); \
122 pthread_mutex_unlock(&func_mutex); \
125 #define LOAD_CLOSE_FUNC() \
127 pthread_mutex_lock(&func_mutex); \
129 _close = (int (*)(int)) dlsym(RTLD_NEXT, "close"); \
130 pthread_mutex_unlock(&func_mutex); \
133 #define LOAD_FOPEN_FUNC() \
135 pthread_mutex_lock(&func_mutex); \
137 _fopen = (FILE* (*)(const char *, const char*)) dlsym(RTLD_NEXT, "fopen"); \
138 pthread_mutex_unlock(&func_mutex); \
141 #define LOAD_FOPEN64_FUNC() \
143 pthread_mutex_lock(&func_mutex); \
145 _fopen64 = (FILE* (*)(const char *, const char*)) dlsym(RTLD_NEXT, "fopen64"); \
146 pthread_mutex_unlock(&func_mutex); \
149 #define LOAD_FCLOSE_FUNC() \
151 pthread_mutex_lock(&func_mutex); \
153 _fclose = (int (*)(FILE *)) dlsym(RTLD_NEXT, "fclose"); \
154 pthread_mutex_unlock(&func_mutex); \
157 static void debug(const char *format
, ...) PA_GCC_PRINTF_ATTR(1,2);
159 static void debug(const char *format
, ...) {
161 if (getenv("PADSP_DEBUG")) {
162 va_start(ap
, format
);
163 vfprintf(stderr
, format
, ap
);
168 static pthread_key_t recursion_key
;
170 static void recursion_key_alloc(void) {
171 pthread_key_create(&recursion_key
, NULL
);
174 static int function_enter(void) {
175 /* Avoid recursive calls */
176 static pthread_once_t recursion_key_once
= PTHREAD_ONCE_INIT
;
177 pthread_once(&recursion_key_once
, recursion_key_alloc
);
179 if (pthread_getspecific(recursion_key
))
182 pthread_setspecific(recursion_key
, (void*) 1);
186 static void function_exit(void) {
187 pthread_setspecific(recursion_key
, NULL
);
190 static void fd_info_free(fd_info
*i
) {
193 debug(__FILE__
": freeing fd info (fd=%i)\n", i
->app_fd
);
198 pa_threaded_mainloop_stop(i
->mainloop
);
201 pa_stream_disconnect(i
->stream
);
202 pa_stream_unref(i
->stream
);
206 pa_context_disconnect(i
->context
);
207 pa_context_unref(i
->context
);
211 pa_threaded_mainloop_free(i
->mainloop
);
213 if (i
->app_fd
>= 0) {
218 if (i
->thread_fd
>= 0) {
220 _close(i
->thread_fd
);
225 pthread_mutex_destroy(&i
->mutex
);
229 static fd_info
*fd_info_ref(fd_info
*i
) {
232 pthread_mutex_lock(&i
->mutex
);
236 /* debug(__FILE__": ref++, now %i\n", i->ref); */
237 pthread_mutex_unlock(&i
->mutex
);
242 static void fd_info_unref(fd_info
*i
) {
244 pthread_mutex_lock(&i
->mutex
);
247 /* debug(__FILE__": ref--, now %i\n", i->ref); */
248 pthread_mutex_unlock(&i
->mutex
);
254 static void context_state_cb(pa_context
*c
, void *userdata
) {
255 fd_info
*i
= userdata
;
258 switch (pa_context_get_state(c
)) {
259 case PA_CONTEXT_READY
:
260 case PA_CONTEXT_TERMINATED
:
261 case PA_CONTEXT_FAILED
:
262 pa_threaded_mainloop_signal(i
->mainloop
, 0);
265 case PA_CONTEXT_UNCONNECTED
:
266 case PA_CONTEXT_CONNECTING
:
267 case PA_CONTEXT_AUTHORIZING
:
268 case PA_CONTEXT_SETTING_NAME
:
273 static void reset_params(fd_info
*i
) {
276 i
->sample_spec
.format
= PA_SAMPLE_ULAW
;
277 i
->sample_spec
.channels
= 1;
278 i
->sample_spec
.rate
= 8000;
279 i
->fragment_size
= 1024;
283 static char *client_name(char *buf
, size_t n
) {
286 if (pa_get_binary_name(p
, sizeof(p
)))
287 snprintf(buf
, n
, "oss[%s]", pa_path_get_filename(p
));
289 snprintf(buf
, n
, "oss");
294 static void atfork_prepare(void) {
297 debug(__FILE__
": atfork_prepare() enter\n");
301 pthread_mutex_lock(&fd_infos_mutex
);
303 for (i
= fd_infos
; i
; i
= i
->next
) {
304 pthread_mutex_lock(&i
->mutex
);
305 pa_threaded_mainloop_lock(i
->mainloop
);
308 pthread_mutex_lock(&func_mutex
);
311 debug(__FILE__
": atfork_prepare() exit\n");
314 static void atfork_parent(void) {
317 debug(__FILE__
": atfork_parent() enter\n");
319 pthread_mutex_unlock(&func_mutex
);
321 for (i
= fd_infos
; i
; i
= i
->next
) {
322 pa_threaded_mainloop_unlock(i
->mainloop
);
323 pthread_mutex_unlock(&i
->mutex
);
326 pthread_mutex_unlock(&fd_infos_mutex
);
330 debug(__FILE__
": atfork_parent() exit\n");
333 static void atfork_child(void) {
336 debug(__FILE__
": atfork_child() enter\n");
338 /* We do only the bare minimum to get all fds closed */
339 pthread_mutex_init(&func_mutex
, NULL
);
340 pthread_mutex_init(&fd_infos_mutex
, NULL
);
342 for (i
= fd_infos
; i
; i
= i
->next
) {
343 pthread_mutex_init(&i
->mutex
, NULL
);
346 pa_context_disconnect(i
->context
);
347 pa_context_unref(i
->context
);
352 pa_stream_unref(i
->stream
);
356 if (i
->app_fd
>= 0) {
361 if (i
->thread_fd
>= 0) {
371 debug(__FILE__
": atfork_child() exit\n");
374 static void install_atfork(void) {
375 pthread_atfork(atfork_prepare
, atfork_parent
, atfork_child
);
378 static fd_info
* fd_info_new(fd_info_type_t type
, int *_errno
) {
380 int sfds
[2] = { -1, -1 };
382 static pthread_once_t install_atfork_once
= PTHREAD_ONCE_INIT
;
384 debug(__FILE__
": fd_info_new()\n");
386 signal(SIGPIPE
, SIG_IGN
); /* Yes, ugly as hell */
388 pthread_once(&install_atfork_once
, install_atfork
);
390 if (!(i
= malloc(sizeof(fd_info
)))) {
395 i
->app_fd
= i
->thread_fd
= -1;
402 pthread_mutex_init(&i
->mutex
, NULL
);
406 PA_LLIST_INIT(fd_info
, i
);
410 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, sfds
) < 0) {
412 debug(__FILE__
": socket() failed: %s\n", strerror(errno
));
417 i
->thread_fd
= sfds
[1];
419 if (!(i
->mainloop
= pa_threaded_mainloop_new())) {
421 debug(__FILE__
": pa_threaded_mainloop_new() failed\n");
425 if (!(i
->context
= pa_context_new(pa_threaded_mainloop_get_api(i
->mainloop
), client_name(name
, sizeof(name
))))) {
427 debug(__FILE__
": pa_context_new() failed\n");
431 pa_context_set_state_callback(i
->context
, context_state_cb
, i
);
433 if (pa_context_connect(i
->context
, NULL
, 0, NULL
) < 0) {
434 *_errno
= ECONNREFUSED
;
435 debug(__FILE__
": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
439 pa_threaded_mainloop_lock(i
->mainloop
);
441 if (pa_threaded_mainloop_start(i
->mainloop
) < 0) {
443 debug(__FILE__
": pa_threaded_mainloop_start() failed\n");
444 goto unlock_and_fail
;
447 /* Wait until the context is ready */
448 pa_threaded_mainloop_wait(i
->mainloop
);
450 if (pa_context_get_state(i
->context
) != PA_CONTEXT_READY
) {
451 *_errno
= ECONNREFUSED
;
452 debug(__FILE__
": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
453 goto unlock_and_fail
;
456 pa_threaded_mainloop_unlock(i
->mainloop
);
461 pa_threaded_mainloop_unlock(i
->mainloop
);
471 static void fd_info_add_to_list(fd_info
*i
) {
474 pthread_mutex_lock(&fd_infos_mutex
);
475 PA_LLIST_PREPEND(fd_info
, fd_infos
, i
);
476 pthread_mutex_unlock(&fd_infos_mutex
);
481 static void fd_info_remove_from_list(fd_info
*i
) {
484 pthread_mutex_lock(&fd_infos_mutex
);
485 PA_LLIST_REMOVE(fd_info
, fd_infos
, i
);
486 pthread_mutex_unlock(&fd_infos_mutex
);
491 static fd_info
* fd_info_find(int fd
) {
494 pthread_mutex_lock(&fd_infos_mutex
);
496 for (i
= fd_infos
; i
; i
= i
->next
)
497 if (i
->app_fd
== fd
&& !i
->unusable
) {
502 pthread_mutex_unlock(&fd_infos_mutex
);
507 static void fix_metrics(fd_info
*i
) {
509 char t
[PA_SAMPLE_SPEC_SNPRINT_MAX
];
511 fs
= pa_frame_size(&i
->sample_spec
);
512 i
->fragment_size
= (i
->fragment_size
/fs
)*fs
;
514 if (i
->n_fragments
< 2)
517 if (i
->fragment_size
<= 0)
518 if ((i
->fragment_size
= pa_bytes_per_second(&i
->sample_spec
) / 2 / i
->n_fragments
) <= 0)
519 i
->fragment_size
= 1024;
521 debug(__FILE__
": sample spec: %s\n", pa_sample_spec_snprint(t
, sizeof(t
), &i
->sample_spec
));
522 debug(__FILE__
": fixated metrics to %i fragments, %li bytes each.\n", i
->n_fragments
, (long)i
->fragment_size
);
525 static void stream_request_cb(pa_stream
*s
, size_t length
, void *userdata
) {
526 fd_info
*i
= userdata
;
530 pa_mainloop_api
*api
;
531 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
532 api
->io_enable(i
->io_event
, PA_IO_EVENT_INPUT
);
536 static void stream_latency_update_cb(pa_stream
*s
, void *userdata
) {
537 fd_info
*i
= userdata
;
540 pa_threaded_mainloop_signal(i
->mainloop
, 0);
543 static void fd_info_shutdown(fd_info
*i
) {
547 pa_mainloop_api
*api
;
548 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
549 api
->io_free(i
->io_event
);
553 if (i
->thread_fd
>= 0) {
559 static int fd_info_copy_data(fd_info
*i
, int force
) {
565 if ((n
= pa_stream_writable_size(i
->stream
)) == (size_t) -1) {
566 debug(__FILE__
": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
570 while (n
>= i
->fragment_size
|| force
) {
574 if (!(i
->buf
= malloc(i
->fragment_size
))) {
575 debug(__FILE__
": malloc() failed.\n");
580 if ((r
= read(i
->thread_fd
, i
->buf
, i
->fragment_size
)) <= 0) {
585 debug(__FILE__
": read(): %s\n", r
== 0 ? "EOF" : strerror(errno
));
589 if (pa_stream_write(i
->stream
, i
->buf
, r
, free
, 0, PA_SEEK_RELATIVE
) < 0) {
590 debug(__FILE__
": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
596 assert(n
>= (size_t) r
);
601 pa_mainloop_api
*api
;
602 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
603 api
->io_enable(i
->io_event
, n
>= i
->fragment_size
? PA_IO_EVENT_INPUT
: 0);
609 static void stream_state_cb(pa_stream
*s
, void * userdata
) {
610 fd_info
*i
= userdata
;
613 switch (pa_stream_get_state(s
)) {
615 case PA_STREAM_READY
:
616 debug(__FILE__
": stream established.\n");
619 case PA_STREAM_FAILED
:
620 debug(__FILE__
": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
624 case PA_STREAM_TERMINATED
:
625 case PA_STREAM_UNCONNECTED
:
626 case PA_STREAM_CREATING
:
631 static int create_stream(fd_info
*i
) {
639 if (!(i
->stream
= pa_stream_new(i
->context
, "Audio Stream", &i
->sample_spec
, NULL
))) {
640 debug(__FILE__
": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
644 pa_stream_set_state_callback(i
->stream
, stream_state_cb
, i
);
645 pa_stream_set_write_callback(i
->stream
, stream_request_cb
, i
);
646 pa_stream_set_latency_update_callback(i
->stream
, stream_latency_update_cb
, i
);
648 memset(&attr
, 0, sizeof(attr
));
649 attr
.maxlength
= i
->fragment_size
* (i
->n_fragments
+1);
650 attr
.tlength
= i
->fragment_size
* i
->n_fragments
;
651 attr
.prebuf
= i
->fragment_size
;
652 attr
.minreq
= i
->fragment_size
;
654 if (pa_stream_connect_playback(i
->stream
, NULL
, &attr
, PA_STREAM_INTERPOLATE_TIMING
|PA_STREAM_AUTO_TIMING_UPDATE
, NULL
, NULL
) < 0) {
655 debug(__FILE__
": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
659 n
= i
->fragment_size
;
660 setsockopt(i
->app_fd
, SOL_SOCKET
, SO_SNDBUF
, &n
, sizeof(n
));
661 n
= i
->fragment_size
;
662 setsockopt(i
->thread_fd
, SOL_SOCKET
, SO_RCVBUF
, &n
, sizeof(n
));
670 static void free_stream(fd_info
*i
) {
674 pa_stream_disconnect(i
->stream
);
675 pa_stream_unref(i
->stream
);
680 static void io_event_cb(pa_mainloop_api
*api
, pa_io_event
*e
, int fd
, pa_io_event_flags_t flags
, void *userdata
) {
681 fd_info
*i
= userdata
;
683 pa_threaded_mainloop_signal(i
->mainloop
, 0);
685 if (flags
& PA_IO_EVENT_INPUT
) {
688 api
->io_enable(e
, 0);
690 if (create_stream(i
) < 0)
694 if (fd_info_copy_data(i
, 0) < 0)
698 } else if (flags
& (PA_IO_EVENT_HANGUP
|PA_IO_EVENT_ERROR
))
704 /* We can't do anything better than removing the event source */
708 static int dsp_open(int flags
, int *_errno
) {
710 pa_mainloop_api
*api
;
714 if ((flags
!= O_WRONLY
) && (flags
!= (O_WRONLY
|O_NONBLOCK
))) {
719 if (!(i
= fd_info_new(FD_INFO_PLAYBACK
, _errno
)))
722 shutdown(i
->thread_fd
, SHUT_WR
);
723 shutdown(i
->app_fd
, SHUT_RD
);
725 if ((flags
& O_NONBLOCK
) == O_NONBLOCK
) {
726 if ((f
= fcntl(i
->app_fd
, F_GETFL
)) >= 0)
727 fcntl(i
->app_fd
, F_SETFL
, f
|O_NONBLOCK
);
729 if ((f
= fcntl(i
->thread_fd
, F_GETFL
)) >= 0)
730 fcntl(i
->thread_fd
, F_SETFL
, f
|O_NONBLOCK
);
732 fcntl(i
->app_fd
, F_SETFD
, FD_CLOEXEC
);
733 fcntl(i
->thread_fd
, F_SETFD
, FD_CLOEXEC
);
735 pa_threaded_mainloop_lock(i
->mainloop
);
736 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
737 if (!(i
->io_event
= api
->io_new(api
, i
->thread_fd
, PA_IO_EVENT_INPUT
, io_event_cb
, i
)))
740 pa_threaded_mainloop_unlock(i
->mainloop
);
742 debug(__FILE__
": dsp_open() succeeded, fd=%i\n", i
->app_fd
);
744 fd_info_add_to_list(i
);
751 pa_threaded_mainloop_unlock(i
->mainloop
);
758 debug(__FILE__
": dsp_open() failed\n");
763 static int mixer_open(int flags
, int *_errno
) {
769 /* if (!(i = fd_info_new(FD_INFO_MIXER))) */
774 static int sndstat_open(int flags
, int *_errno
) {
775 static const char sndstat
[] =
776 "Sound Driver:3.8.1a-980706 (Polypaudio Virtual OSS)\n"
778 "Config options: 0\n"
780 "Installed drivers:\n"
781 "Type 255: Polypaudio Virtual OSS\n"
784 "Polypaudio Virtual OSS\n"
787 "0: Polypaudio Virtual OSS\n"
789 "Synth devices: NOT ENABLED IN CONFIG\n"
796 "0: Polypaudio Virtual OSS\n";
798 char fn
[] = "/tmp/padsp-sndstat-XXXXXX";
803 debug(__FILE__
": sndstat_open()\n");
805 if (flags
!= O_RDONLY
&& flags
!= (O_RDONLY
|O_LARGEFILE
)) {
807 debug(__FILE__
": bad access!\n");
818 debug(__FILE__
": mkstemp() failed: %s\n", strerror(errno
));
824 if (write(fd
, sndstat
, sizeof(sndstat
) -1) != sizeof(sndstat
)-1) {
826 debug(__FILE__
": write() failed: %s\n", strerror(errno
));
830 if (lseek(fd
, SEEK_SET
, 0) < 0) {
832 debug(__FILE__
": lseek() failed: %s\n", strerror(errno
));
844 int open(const char *filename
, int flags
, ...) {
849 debug(__FILE__
": open(%s)\n", filename
);
851 va_start(args
, flags
);
853 mode
= va_arg(args
, mode_t
);
856 if (!function_enter()) {
858 return _open(filename
, flags
, mode
);
861 if (strcmp(filename
, "/dev/dsp") == 0 || strcmp(filename
, "/dev/adsp") == 0) {
862 r
= dsp_open(flags
, &_errno
);
863 } else if (strcmp(filename
, "/dev/mixer") == 0) {
864 r
= mixer_open(flags
, &_errno
);
865 } else if (strcmp(filename
, "/dev/sndstat") == 0) {
866 r
= sndstat_open(flags
, &_errno
);
870 return _open(filename
, flags
, mode
);
881 static int mixer_ioctl(fd_info
*i
, unsigned long request
, void*argp
, int *_errno
) {
886 static int map_format(int *fmt
, pa_sample_spec
*ss
) {
890 ss
->format
= PA_SAMPLE_ULAW
;
894 ss
->format
= PA_SAMPLE_ALAW
;
901 ss
->format
= PA_SAMPLE_U8
;
908 ss
->format
= PA_SAMPLE_S16BE
;
915 ss
->format
= PA_SAMPLE_S16LE
;
919 ss
->format
= PA_SAMPLE_S16NE
;
927 static int map_format_back(pa_sample_format_t format
) {
929 case PA_SAMPLE_S16LE
: return AFMT_S16_LE
;
930 case PA_SAMPLE_S16BE
: return AFMT_S16_BE
;
931 case PA_SAMPLE_ULAW
: return AFMT_MU_LAW
;
932 case PA_SAMPLE_ALAW
: return AFMT_A_LAW
;
933 case PA_SAMPLE_U8
: return AFMT_U8
;
939 static void success_cb(pa_stream
*s
, int success
, void *userdata
) {
940 fd_info
*i
= userdata
;
945 i
->operation_success
= success
;
946 pa_threaded_mainloop_signal(i
->mainloop
, 0);
949 static int dsp_flush_socket(fd_info
*i
) {
952 if (i
->thread_fd
< 0)
955 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0) {
956 debug(__FILE__
": SIOCINQ: %s\n", strerror(errno
));
964 k
= (size_t) l
> sizeof(buf
) ? sizeof(buf
) : (size_t) l
;
965 if (read(i
->thread_fd
, buf
, k
) < 0)
966 debug(__FILE__
": read(): %s\n", strerror(errno
));
973 static int dsp_empty_socket(fd_info
*i
) {
976 /* Empty the socket */
980 if (i
->thread_fd
< 0)
983 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0) {
984 debug(__FILE__
": SIOCINQ: %s\n", strerror(errno
));
993 pa_threaded_mainloop_wait(i
->mainloop
);
999 static int dsp_drain(fd_info
*i
) {
1000 pa_operation
*o
= NULL
;
1006 debug(__FILE__
": Draining.\n");
1008 pa_threaded_mainloop_lock(i
->mainloop
);
1010 if (dsp_empty_socket(i
) < 0)
1016 debug(__FILE__
": Really draining.\n");
1018 if (!(o
= pa_stream_drain(i
->stream
, success_cb
, i
))) {
1019 debug(__FILE__
": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1023 i
->operation_success
= 0;
1024 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1025 if (!i
->stream
|| pa_stream_get_state(i
->stream
) != PA_STREAM_READY
)
1028 pa_threaded_mainloop_wait(i
->mainloop
);
1031 if (!i
->operation_success
) {
1032 debug(__FILE__
": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i
->context
)));
1041 pa_operation_unref(o
);
1043 pa_threaded_mainloop_unlock(i
->mainloop
);
1048 static int dsp_trigger(fd_info
*i
) {
1049 pa_operation
*o
= NULL
;
1055 pa_threaded_mainloop_lock(i
->mainloop
);
1057 if (dsp_empty_socket(i
) < 0)
1060 debug(__FILE__
": Triggering.\n");
1062 if (!(o
= pa_stream_trigger(i
->stream
, success_cb
, i
))) {
1063 debug(__FILE__
": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1067 i
->operation_success
= 0;
1068 while (!pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1069 if (!i
->stream
|| pa_stream_get_state(i
->stream
) != PA_STREAM_READY
)
1072 pa_threaded_mainloop_wait(i
->mainloop
);
1075 if (!i
->operation_success
) {
1076 debug(__FILE__
": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1085 pa_operation_unref(o
);
1087 pa_threaded_mainloop_unlock(i
->mainloop
);
1092 static int dsp_ioctl(fd_info
*i
, unsigned long request
, void*argp
, int *_errno
) {
1096 case SNDCTL_DSP_SETFMT
: {
1097 debug(__FILE__
": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp
);
1099 pa_threaded_mainloop_lock(i
->mainloop
);
1101 if (*(int*) argp
== AFMT_QUERY
)
1102 *(int*) argp
= map_format_back(i
->sample_spec
.format
);
1104 map_format((int*) argp
, &i
->sample_spec
);
1108 pa_threaded_mainloop_unlock(i
->mainloop
);
1112 case SNDCTL_DSP_SPEED
: {
1117 debug(__FILE__
": SNDCTL_DSP_SPEED: %i\n", *(int*) argp
);
1119 pa_threaded_mainloop_lock(i
->mainloop
);
1121 ss
= i
->sample_spec
;
1122 ss
.rate
= *(int*) argp
;
1124 if ((valid
= pa_sample_spec_valid(&ss
))) {
1125 i
->sample_spec
= ss
;
1129 debug(__FILE__
": ss: %s\n", pa_sample_spec_snprint(t
, sizeof(t
), &i
->sample_spec
));
1131 pa_threaded_mainloop_unlock(i
->mainloop
);
1141 case SNDCTL_DSP_STEREO
:
1142 debug(__FILE__
": SNDCTL_DSP_STEREO: %i\n", *(int*) argp
);
1144 pa_threaded_mainloop_lock(i
->mainloop
);
1146 i
->sample_spec
.channels
= *(int*) argp
? 2 : 1;
1149 pa_threaded_mainloop_unlock(i
->mainloop
);
1152 case SNDCTL_DSP_CHANNELS
: {
1156 debug(__FILE__
": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp
);
1158 pa_threaded_mainloop_lock(i
->mainloop
);
1160 ss
= i
->sample_spec
;
1161 ss
.channels
= *(int*) argp
;
1163 if ((valid
= pa_sample_spec_valid(&ss
))) {
1164 i
->sample_spec
= ss
;
1168 pa_threaded_mainloop_unlock(i
->mainloop
);
1178 case SNDCTL_DSP_GETBLKSIZE
:
1179 debug(__FILE__
": SNDCTL_DSP_GETBLKSIZE\n");
1181 pa_threaded_mainloop_lock(i
->mainloop
);
1184 *(int*) argp
= i
->fragment_size
;
1186 pa_threaded_mainloop_unlock(i
->mainloop
);
1190 case SNDCTL_DSP_SETFRAGMENT
:
1191 debug(__FILE__
": SNDCTL_DSP_SETFRAGMENT: 0x%8x\n", *(int*) argp
);
1193 pa_threaded_mainloop_lock(i
->mainloop
);
1195 i
->fragment_size
= 1 << (*(int*) argp
);
1196 i
->n_fragments
= (*(int*) argp
) >> 16;
1200 pa_threaded_mainloop_unlock(i
->mainloop
);
1204 case SNDCTL_DSP_GETCAPS
:
1205 debug(__FILE__
": SNDCTL_DSP_CAPS\n");
1207 *(int*) argp
= DSP_CAP_MULTI
;
1210 case SNDCTL_DSP_GETODELAY
: {
1213 debug(__FILE__
": SNDCTL_DSP_GETODELAY\n");
1215 pa_threaded_mainloop_lock(i
->mainloop
);
1221 if (!i
->stream
|| pa_stream_get_state(i
->stream
) != PA_STREAM_READY
)
1224 if (pa_stream_get_latency(i
->stream
, &usec
, NULL
) >= 0) {
1225 *(int*) argp
= pa_usec_to_bytes(usec
, &i
->sample_spec
);
1229 if (pa_context_errno(i
->context
) != PA_ERR_NODATA
) {
1230 debug(__FILE__
": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1234 pa_threaded_mainloop_wait(i
->mainloop
);
1237 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0)
1238 debug(__FILE__
": SIOCINQ failed: %s\n", strerror(errno
));
1242 pa_threaded_mainloop_unlock(i
->mainloop
);
1244 debug(__FILE__
": ODELAY: %i\n", *(int*) argp
);
1249 case SNDCTL_DSP_RESET
: {
1250 debug(__FILE__
": SNDCTL_DSP_RESET\n");
1252 pa_threaded_mainloop_lock(i
->mainloop
);
1255 dsp_flush_socket(i
);
1258 pa_threaded_mainloop_unlock(i
->mainloop
);
1262 case SNDCTL_DSP_GETFMTS
: {
1263 debug(__FILE__
": SNDCTL_DSP_GETFMTS\n");
1265 *(int*) argp
= AFMT_MU_LAW
|AFMT_A_LAW
|AFMT_U8
|AFMT_S16_LE
|AFMT_S16_BE
;
1269 case SNDCTL_DSP_POST
:
1270 debug(__FILE__
": SNDCTL_DSP_POST\n");
1272 if (dsp_trigger(i
) < 0)
1276 case SNDCTL_DSP_SYNC
:
1277 debug(__FILE__
": SNDCTL_DSP_SYNC\n");
1279 if (dsp_drain(i
) < 0)
1284 case SNDCTL_DSP_GETOSPACE
: {
1285 audio_buf_info
*bi
= (audio_buf_info
*) argp
;
1289 debug(__FILE__
": SNDCTL_DSP_GETOSPACE\n");
1291 pa_threaded_mainloop_lock(i
->mainloop
);
1296 if ((k
= pa_stream_writable_size(i
->stream
)) == (size_t) -1)
1297 debug(__FILE__
": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1299 k
= i
->fragment_size
* i
->n_fragments
;
1301 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0) {
1302 debug(__FILE__
": SIOCINQ failed: %s\n", strerror(errno
));
1306 bi
->fragsize
= i
->fragment_size
;
1307 bi
->fragstotal
= i
->n_fragments
;
1308 bi
->bytes
= k
> (size_t) l
? k
- l
: 0;
1309 bi
->fragments
= bi
->bytes
/ bi
->fragsize
;
1311 pa_threaded_mainloop_unlock(i
->mainloop
);
1313 debug(__FILE__
": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi
->fragsize
, bi
->fragstotal
, bi
->bytes
, bi
->fragments
);
1319 debug(__FILE__
": unknwon ioctl 0x%08lx\n", request
);
1332 int ioctl(int fd
, unsigned long request
, ...) {
1338 debug(__FILE__
": ioctl()\n");
1340 va_start(args
, request
);
1341 argp
= va_arg(args
, void *);
1344 if (!function_enter()) {
1346 return _ioctl(fd
, request
, argp
);
1349 if (!(i
= fd_info_find(fd
))) {
1352 return _ioctl(fd
, request
, argp
);
1355 if (i
->type
== FD_INFO_MIXER
)
1356 r
= mixer_ioctl(i
, request
, argp
, &_errno
);
1358 r
= dsp_ioctl(i
, request
, argp
, &_errno
);
1373 debug(__FILE__
": close()\n");
1375 if (!function_enter()) {
1380 if (!(i
= fd_info_find(fd
))) {
1386 fd_info_remove_from_list(i
);
1394 int open64(const char *filename
, int flags
, ...) {
1398 debug(__FILE__
": open64(%s)\n", filename
);
1400 va_start(args
, flags
);
1401 if (flags
& O_CREAT
)
1402 mode
= va_arg(args
, mode_t
);
1405 if (strcmp(filename
, "/dev/dsp") != 0 &&
1406 strcmp(filename
, "/dev/adsp") != 0 &&
1407 strcmp(filename
, "/dev/sndstat") != 0 &&
1408 strcmp(filename
, "/dev/mixer") != 0) {
1410 return _open64(filename
, flags
, mode
);
1413 return open(filename
, flags
, mode
);
1416 FILE* fopen(const char *filename
, const char *mode
) {
1421 debug(__FILE__
": fopen(%s)\n", filename
);
1423 if (strcmp(filename
, "/dev/dsp") == 0 ||
1424 strcmp(filename
, "/dev/adsp") == 0) {
1426 if (strcmp(mode
, "wb") != 0) {
1432 } else if (strcmp(filename
, "/dev/sndstat") == 0) {
1434 if (strcmp(mode
, "r") != 0) {
1440 } else if (strcmp(filename
, "/dev/mixer") != 0)
1444 return _fopen(filename
, mode
);
1447 if ((fd
= open(filename
, m
)) < 0)
1450 if (!(f
= fdopen(fd
, mode
))) {
1458 FILE *fopen64(const char *filename
, const char *mode
) {
1460 debug(__FILE__
": fopen64(%s)\n", filename
);
1462 if (strcmp(filename
, "/dev/dsp") != 0 &&
1463 strcmp(filename
, "/dev/adsp") != 0 &&
1464 strcmp(filename
, "/dev/sndstat") != 0 &&
1465 strcmp(filename
, "/dev/mixer") != 0) {
1466 LOAD_FOPEN64_FUNC();
1467 return _fopen64(filename
, mode
);
1470 return fopen(filename
, mode
);
1473 int fclose(FILE *f
) {
1476 debug(__FILE__
": fclose()\n");
1478 if (!function_enter()) {
1483 if (!(i
= fd_info_find(fileno(f
)))) {
1489 fd_info_remove_from_list(i
);
1491 /* Dirty trick to avoid that the fd is not freed twice, once by us
1492 * and once by the real fclose() */