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
;
65 int app_fd
, thread_fd
;
67 pa_sample_spec sample_spec
;
71 pa_threaded_mainloop
*mainloop
;
75 pa_io_event
*io_event
;
79 int operation_success
;
81 PA_LLIST_FIELDS(fd_info
);
84 static int dsp_drain(fd_info
*i
);
86 static pthread_mutex_t fd_infos_mutex
= PTHREAD_MUTEX_INITIALIZER
;
87 static pthread_mutex_t func_mutex
= PTHREAD_MUTEX_INITIALIZER
;
89 static PA_LLIST_HEAD(fd_info
, fd_infos
) = NULL
;
91 static int (*_ioctl
)(int, int, void*) = NULL
;
92 static int (*_close
)(int) = NULL
;
93 static int (*_open
)(const char *, int, mode_t
) = NULL
;
94 static FILE* (*_fopen
)(const char *path
, const char *mode
) = NULL
;
95 static int (*_open64
)(const char *, int, mode_t
) = NULL
;
96 static FILE* (*_fopen64
)(const char *path
, const char *mode
) = NULL
;
97 static int (*_fclose
)(FILE *f
) = NULL
;
99 #define LOAD_IOCTL_FUNC() \
101 pthread_mutex_lock(&func_mutex); \
103 _ioctl = (int (*)(int, int, void*)) dlsym(RTLD_NEXT, "ioctl"); \
104 pthread_mutex_unlock(&func_mutex); \
107 #define LOAD_OPEN_FUNC() \
109 pthread_mutex_lock(&func_mutex); \
111 _open = (int (*)(const char *, int, mode_t)) dlsym(RTLD_NEXT, "open"); \
112 pthread_mutex_unlock(&func_mutex); \
115 #define LOAD_OPEN64_FUNC() \
117 pthread_mutex_lock(&func_mutex); \
119 _open64 = (int (*)(const char *, int, mode_t)) dlsym(RTLD_NEXT, "open64"); \
120 pthread_mutex_unlock(&func_mutex); \
123 #define LOAD_CLOSE_FUNC() \
125 pthread_mutex_lock(&func_mutex); \
127 _close = (int (*)(int)) dlsym(RTLD_NEXT, "close"); \
128 pthread_mutex_unlock(&func_mutex); \
131 #define LOAD_FOPEN_FUNC() \
133 pthread_mutex_lock(&func_mutex); \
135 _fopen = (FILE* (*)(const char *, const char*)) dlsym(RTLD_NEXT, "fopen"); \
136 pthread_mutex_unlock(&func_mutex); \
139 #define LOAD_FOPEN64_FUNC() \
141 pthread_mutex_lock(&func_mutex); \
143 _fopen64 = (FILE* (*)(const char *, const char*)) dlsym(RTLD_NEXT, "fopen64"); \
144 pthread_mutex_unlock(&func_mutex); \
147 #define LOAD_FCLOSE_FUNC() \
149 pthread_mutex_lock(&func_mutex); \
151 _fclose = (int (*)(FILE *)) dlsym(RTLD_NEXT, "fclose"); \
152 pthread_mutex_unlock(&func_mutex); \
155 static void debug(const char *format
, ...) PA_GCC_PRINTF_ATTR(1,2);
157 static void debug(const char *format
, ...) {
159 if (getenv("PADSP_DEBUG")) {
160 va_start(ap
, format
);
161 vfprintf(stderr
, format
, ap
);
166 static pthread_key_t recursion_key
;
168 static void recursion_key_alloc(void) {
169 pthread_key_create(&recursion_key
, NULL
);
172 static int function_enter(void) {
173 /* Avoid recursive calls */
174 static pthread_once_t recursion_key_once
= PTHREAD_ONCE_INIT
;
175 pthread_once(&recursion_key_once
, recursion_key_alloc
);
177 if (pthread_getspecific(recursion_key
))
180 pthread_setspecific(recursion_key
, (void*) 1);
184 static void function_exit(void) {
185 pthread_setspecific(recursion_key
, NULL
);
188 static void fd_info_free(fd_info
*i
) {
191 debug(__FILE__
": freeing fd info (fd=%i)\n", i
->app_fd
);
196 pa_threaded_mainloop_stop(i
->mainloop
);
199 pa_stream_disconnect(i
->stream
);
200 pa_stream_unref(i
->stream
);
204 pa_context_disconnect(i
->context
);
205 pa_context_unref(i
->context
);
209 pa_threaded_mainloop_free(i
->mainloop
);
211 if (i
->app_fd
>= 0) {
216 if (i
->thread_fd
>= 0) {
218 _close(i
->thread_fd
);
223 pthread_mutex_destroy(&i
->mutex
);
227 static fd_info
*fd_info_ref(fd_info
*i
) {
230 pthread_mutex_lock(&i
->mutex
);
234 /* debug(__FILE__": ref++, now %i\n", i->ref); */
235 pthread_mutex_unlock(&i
->mutex
);
240 static void fd_info_unref(fd_info
*i
) {
242 pthread_mutex_lock(&i
->mutex
);
245 /* debug(__FILE__": ref--, now %i\n", i->ref); */
246 pthread_mutex_unlock(&i
->mutex
);
252 static void context_state_cb(pa_context
*c
, void *userdata
) {
253 fd_info
*i
= userdata
;
256 switch (pa_context_get_state(c
)) {
257 case PA_CONTEXT_READY
:
258 case PA_CONTEXT_TERMINATED
:
259 case PA_CONTEXT_FAILED
:
260 pa_threaded_mainloop_signal(i
->mainloop
, 0);
263 case PA_CONTEXT_UNCONNECTED
:
264 case PA_CONTEXT_CONNECTING
:
265 case PA_CONTEXT_AUTHORIZING
:
266 case PA_CONTEXT_SETTING_NAME
:
271 static void reset_params(fd_info
*i
) {
274 i
->sample_spec
.format
= PA_SAMPLE_ULAW
;
275 i
->sample_spec
.channels
= 1;
276 i
->sample_spec
.rate
= 8000;
277 i
->fragment_size
= 1024;
281 static fd_info
* fd_info_new(fd_info_type_t type
, int *_errno
) {
283 int sfds
[2] = { -1, -1 };
285 debug(__FILE__
": fd_info_new()\n");
287 signal(SIGPIPE
, SIG_IGN
); /* Yes, ugly as hell */
289 if (!(i
= malloc(sizeof(fd_info
)))) {
294 i
->app_fd
= i
->thread_fd
= -1;
301 pthread_mutex_init(&i
->mutex
, NULL
);
304 PA_LLIST_INIT(fd_info
, i
);
308 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, sfds
) < 0) {
310 debug(__FILE__
": socket() failed: %s\n", strerror(errno
));
315 i
->thread_fd
= sfds
[1];
317 if (!(i
->mainloop
= pa_threaded_mainloop_new())) {
319 debug(__FILE__
": pa_threaded_mainloop_new() failed\n");
323 if (!(i
->context
= pa_context_new(pa_threaded_mainloop_get_api(i
->mainloop
), "oss"))) {
325 debug(__FILE__
": pa_context_new() failed\n");
329 pa_context_set_state_callback(i
->context
, context_state_cb
, i
);
331 if (pa_context_connect(i
->context
, NULL
, 0, NULL
) < 0) {
332 *_errno
= ECONNREFUSED
;
333 debug(__FILE__
": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
337 pa_threaded_mainloop_lock(i
->mainloop
);
339 if (pa_threaded_mainloop_start(i
->mainloop
) < 0) {
341 debug(__FILE__
": pa_threaded_mainloop_start() failed\n");
342 goto unlock_and_fail
;
345 /* Wait until the context is ready */
346 pa_threaded_mainloop_wait(i
->mainloop
);
348 if (pa_context_get_state(i
->context
) != PA_CONTEXT_READY
) {
349 *_errno
= ECONNREFUSED
;
350 debug(__FILE__
": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
351 goto unlock_and_fail
;
354 pa_threaded_mainloop_unlock(i
->mainloop
);
359 pa_threaded_mainloop_unlock(i
->mainloop
);
369 static void fd_info_add_to_list(fd_info
*i
) {
372 pthread_mutex_lock(&fd_infos_mutex
);
373 PA_LLIST_PREPEND(fd_info
, fd_infos
, i
);
374 pthread_mutex_unlock(&fd_infos_mutex
);
379 static void fd_info_remove_from_list(fd_info
*i
) {
382 pthread_mutex_lock(&fd_infos_mutex
);
383 PA_LLIST_REMOVE(fd_info
, fd_infos
, i
);
384 pthread_mutex_unlock(&fd_infos_mutex
);
389 static fd_info
* fd_info_find(int fd
) {
392 pthread_mutex_lock(&fd_infos_mutex
);
394 for (i
= fd_infos
; i
; i
= i
->next
)
395 if (i
->app_fd
== fd
) {
400 pthread_mutex_unlock(&fd_infos_mutex
);
405 static void fix_metrics(fd_info
*i
) {
407 char t
[PA_SAMPLE_SPEC_SNPRINT_MAX
];
409 fs
= pa_frame_size(&i
->sample_spec
);
410 i
->fragment_size
= (i
->fragment_size
/fs
)*fs
;
412 if (i
->n_fragments
< 2)
415 if (i
->fragment_size
<= 0)
416 if ((i
->fragment_size
= pa_bytes_per_second(&i
->sample_spec
) / 2 / i
->n_fragments
) <= 0)
417 i
->fragment_size
= 1024;
419 debug(__FILE__
": sample spec: %s\n", pa_sample_spec_snprint(t
, sizeof(t
), &i
->sample_spec
));
420 debug(__FILE__
": fixated metrics to %i fragments, %li bytes each.\n", i
->n_fragments
, (long)i
->fragment_size
);
423 static void stream_request_cb(pa_stream
*s
, size_t length
, void *userdata
) {
424 fd_info
*i
= userdata
;
428 pa_mainloop_api
*api
;
429 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
430 api
->io_enable(i
->io_event
, PA_IO_EVENT_INPUT
);
434 static void stream_latency_update_cb(pa_stream
*s
, void *userdata
) {
435 fd_info
*i
= userdata
;
438 pa_threaded_mainloop_signal(i
->mainloop
, 0);
441 static void fd_info_shutdown(fd_info
*i
) {
445 pa_mainloop_api
*api
;
446 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
447 api
->io_free(i
->io_event
);
451 if (i
->thread_fd
>= 0) {
457 static int fd_info_copy_data(fd_info
*i
, int force
) {
463 if ((n
= pa_stream_writable_size(i
->stream
)) == (size_t) -1) {
464 debug(__FILE__
": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
468 while (n
>= i
->fragment_size
|| force
) {
472 if (!(i
->buf
= malloc(i
->fragment_size
))) {
473 debug(__FILE__
": malloc() failed.\n");
478 if ((r
= read(i
->thread_fd
, i
->buf
, i
->fragment_size
)) <= 0) {
483 debug(__FILE__
": read(): %s\n", r
== 0 ? "EOF" : strerror(errno
));
487 if (pa_stream_write(i
->stream
, i
->buf
, r
, free
, 0, PA_SEEK_RELATIVE
) < 0) {
488 debug(__FILE__
": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
494 assert(n
>= (size_t) r
);
499 pa_mainloop_api
*api
;
500 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
501 api
->io_enable(i
->io_event
, n
>= i
->fragment_size
? PA_IO_EVENT_INPUT
: 0);
507 static void stream_state_cb(pa_stream
*s
, void * userdata
) {
508 fd_info
*i
= userdata
;
511 switch (pa_stream_get_state(s
)) {
513 case PA_STREAM_READY
:
514 debug(__FILE__
": stream established.\n");
517 case PA_STREAM_FAILED
:
518 debug(__FILE__
": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
522 case PA_STREAM_TERMINATED
:
523 case PA_STREAM_UNCONNECTED
:
524 case PA_STREAM_CREATING
:
529 static int create_stream(fd_info
*i
) {
537 if (!(i
->stream
= pa_stream_new(i
->context
, "audio stream", &i
->sample_spec
, NULL
))) {
538 debug(__FILE__
": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
542 pa_stream_set_state_callback(i
->stream
, stream_state_cb
, i
);
543 pa_stream_set_write_callback(i
->stream
, stream_request_cb
, i
);
544 pa_stream_set_latency_update_callback(i
->stream
, stream_latency_update_cb
, i
);
546 memset(&attr
, 0, sizeof(attr
));
547 attr
.maxlength
= i
->fragment_size
* (i
->n_fragments
+1);
548 attr
.tlength
= i
->fragment_size
* i
->n_fragments
;
549 attr
.prebuf
= i
->fragment_size
;
550 attr
.minreq
= i
->fragment_size
;
552 if (pa_stream_connect_playback(i
->stream
, NULL
, &attr
, PA_STREAM_INTERPOLATE_TIMING
|PA_STREAM_AUTO_TIMING_UPDATE
, NULL
, NULL
) < 0) {
553 debug(__FILE__
": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
557 n
= i
->fragment_size
;
558 setsockopt(i
->app_fd
, SOL_SOCKET
, SO_SNDBUF
, &n
, sizeof(n
));
559 n
= i
->fragment_size
;
560 setsockopt(i
->thread_fd
, SOL_SOCKET
, SO_RCVBUF
, &n
, sizeof(n
));
568 static void free_stream(fd_info
*i
) {
572 pa_stream_disconnect(i
->stream
);
573 pa_stream_unref(i
->stream
);
578 static void io_event_cb(pa_mainloop_api
*api
, pa_io_event
*e
, int fd
, pa_io_event_flags_t flags
, void *userdata
) {
579 fd_info
*i
= userdata
;
581 pa_threaded_mainloop_signal(i
->mainloop
, 0);
583 if (flags
& PA_IO_EVENT_INPUT
) {
586 api
->io_enable(e
, 0);
588 if (create_stream(i
) < 0)
592 if (fd_info_copy_data(i
, 0) < 0)
596 } else if (flags
& (PA_IO_EVENT_HANGUP
|PA_IO_EVENT_ERROR
))
602 /* We can't do anything better than removing the event source */
606 static int dsp_open(int flags
, int *_errno
) {
608 pa_mainloop_api
*api
;
612 if ((flags
!= O_WRONLY
) && (flags
!= (O_WRONLY
|O_NONBLOCK
))) {
617 if (!(i
= fd_info_new(FD_INFO_PLAYBACK
, _errno
)))
620 shutdown(i
->thread_fd
, SHUT_WR
);
621 shutdown(i
->app_fd
, SHUT_RD
);
623 if ((flags
& O_NONBLOCK
) == O_NONBLOCK
) {
624 if ((f
= fcntl(i
->app_fd
, F_GETFL
)) >= 0)
625 fcntl(i
->app_fd
, F_SETFL
, f
|O_NONBLOCK
);
627 if ((f
= fcntl(i
->thread_fd
, F_GETFL
)) >= 0)
628 fcntl(i
->thread_fd
, F_SETFL
, f
|O_NONBLOCK
);
630 fcntl(i
->app_fd
, F_SETFD
, FD_CLOEXEC
);
631 fcntl(i
->thread_fd
, F_SETFD
, FD_CLOEXEC
);
633 pa_threaded_mainloop_lock(i
->mainloop
);
634 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
635 if (!(i
->io_event
= api
->io_new(api
, i
->thread_fd
, PA_IO_EVENT_INPUT
, io_event_cb
, i
)))
638 pa_threaded_mainloop_unlock(i
->mainloop
);
640 debug(__FILE__
": dsp_open() succeeded, fd=%i\n", i
->app_fd
);
642 fd_info_add_to_list(i
);
649 pa_threaded_mainloop_unlock(i
->mainloop
);
656 debug(__FILE__
": dsp_open() failed\n");
661 static int mixer_open(int flags
, int *_errno
) {
667 /* if (!(i = fd_info_new(FD_INFO_MIXER))) */
672 int open(const char *filename
, int flags
, ...) {
677 va_start(args
, flags
);
679 mode
= va_arg(args
, mode_t
);
682 if (!function_enter()) {
684 return _open(filename
, flags
, mode
);
687 debug(__FILE__
": open()\n");
689 if (strcmp(filename
, "/dev/dsp") == 0 || strcmp(filename
, "/dev/adsp") == 0) {
690 r
= dsp_open(flags
, &_errno
);
691 } else if (strcmp(filename
, "/dev/mixer") == 0) {
692 r
= mixer_open(flags
, &_errno
);
696 return _open(filename
, flags
, mode
);
707 static int mixer_ioctl(fd_info
*i
, unsigned long request
, void*argp
, int *_errno
) {
712 static int map_format(int *fmt
, pa_sample_spec
*ss
) {
716 ss
->format
= PA_SAMPLE_ULAW
;
720 ss
->format
= PA_SAMPLE_ALAW
;
727 ss
->format
= PA_SAMPLE_U8
;
734 ss
->format
= PA_SAMPLE_S16BE
;
741 ss
->format
= PA_SAMPLE_S16LE
;
745 ss
->format
= PA_SAMPLE_S16NE
;
753 static int map_format_back(pa_sample_format_t format
) {
755 case PA_SAMPLE_S16LE
: return AFMT_S16_LE
;
756 case PA_SAMPLE_S16BE
: return AFMT_S16_BE
;
757 case PA_SAMPLE_ULAW
: return AFMT_MU_LAW
;
758 case PA_SAMPLE_ALAW
: return AFMT_A_LAW
;
759 case PA_SAMPLE_U8
: return AFMT_U8
;
765 static void success_cb(pa_stream
*s
, int success
, void *userdata
) {
766 fd_info
*i
= userdata
;
771 i
->operation_success
= success
;
772 pa_threaded_mainloop_signal(i
->mainloop
, 0);
775 static int dsp_empty_socket(fd_info
*i
) {
778 /* Empty the socket */
782 if (i
->thread_fd
< 0)
785 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0) {
786 debug(__FILE__
": SIOCINQ: %s\n", strerror(errno
));
793 pa_threaded_mainloop_wait(i
->mainloop
);
799 static int dsp_drain(fd_info
*i
) {
800 pa_operation
*o
= NULL
;
806 debug(__FILE__
": Draining.\n");
808 pa_threaded_mainloop_lock(i
->mainloop
);
810 if (dsp_empty_socket(i
) < 0)
816 debug(__FILE__
": Really draining.\n");
818 if (!(o
= pa_stream_drain(i
->stream
, success_cb
, i
))) {
819 debug(__FILE__
": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
823 i
->operation_success
= 0;
824 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
825 if (!i
->stream
|| pa_stream_get_state(i
->stream
) != PA_STREAM_READY
)
828 pa_threaded_mainloop_wait(i
->mainloop
);
831 if (!i
->operation_success
) {
832 debug(__FILE__
": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i
->context
)));
841 pa_operation_unref(o
);
843 pa_threaded_mainloop_unlock(i
->mainloop
);
848 static int dsp_trigger(fd_info
*i
) {
849 pa_operation
*o
= NULL
;
852 fd_info_copy_data(i
, 1);
857 pa_threaded_mainloop_lock(i
->mainloop
);
859 if (dsp_empty_socket(i
) < 0)
862 debug(__FILE__
": Triggering.\n");
864 if (!(o
= pa_stream_trigger(i
->stream
, success_cb
, i
))) {
865 debug(__FILE__
": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
869 i
->operation_success
= 0;
870 while (!pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
871 if (!i
->stream
|| pa_stream_get_state(i
->stream
) != PA_STREAM_READY
)
874 pa_threaded_mainloop_wait(i
->mainloop
);
877 if (!i
->operation_success
) {
878 debug(__FILE__
": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
887 pa_operation_unref(o
);
889 pa_threaded_mainloop_unlock(i
->mainloop
);
894 static int dsp_ioctl(fd_info
*i
, unsigned long request
, void*argp
, int *_errno
) {
898 case SNDCTL_DSP_SETFMT
: {
899 debug(__FILE__
": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp
);
901 pa_threaded_mainloop_lock(i
->mainloop
);
903 if (*(int*) argp
== AFMT_QUERY
)
904 *(int*) argp
= map_format_back(i
->sample_spec
.format
);
906 map_format((int*) argp
, &i
->sample_spec
);
910 pa_threaded_mainloop_unlock(i
->mainloop
);
914 case SNDCTL_DSP_SPEED
: {
918 debug(__FILE__
": SNDCTL_DSP_SPEED: %i\n", *(int*) argp
);
920 pa_threaded_mainloop_lock(i
->mainloop
);
923 ss
.rate
= *(int*) argp
;
925 if ((valid
= pa_sample_spec_valid(&ss
))) {
930 pa_threaded_mainloop_unlock(i
->mainloop
);
940 case SNDCTL_DSP_STEREO
:
941 debug(__FILE__
": SNDCTL_DSP_STEREO: %i\n", *(int*) argp
);
943 pa_threaded_mainloop_lock(i
->mainloop
);
945 i
->sample_spec
.channels
= *(int*) argp
? 2 : 1;
948 pa_threaded_mainloop_unlock(i
->mainloop
);
951 case SNDCTL_DSP_CHANNELS
: {
955 debug(__FILE__
": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp
);
957 pa_threaded_mainloop_lock(i
->mainloop
);
960 ss
.channels
= *(int*) argp
;
962 if ((valid
= pa_sample_spec_valid(&ss
))) {
967 pa_threaded_mainloop_unlock(i
->mainloop
);
977 case SNDCTL_DSP_GETBLKSIZE
:
978 debug(__FILE__
": SNDCTL_DSP_GETBLKSIZE\n");
980 pa_threaded_mainloop_lock(i
->mainloop
);
983 *(int*) argp
= i
->fragment_size
;
985 pa_threaded_mainloop_unlock(i
->mainloop
);
989 case SNDCTL_DSP_SETFRAGMENT
:
990 debug(__FILE__
": SNDCTL_DSP_SETFRAGMENT: 0x%8x\n", *(int*) argp
);
992 pa_threaded_mainloop_lock(i
->mainloop
);
994 i
->fragment_size
= 1 << (*(int*) argp
);
995 i
->n_fragments
= (*(int*) argp
) >> 16;
999 pa_threaded_mainloop_unlock(i
->mainloop
);
1003 case SNDCTL_DSP_GETCAPS
:
1004 debug(__FILE__
": SNDCTL_DSP_CAPS\n");
1006 *(int*) argp
= DSP_CAP_MULTI
;
1009 case SNDCTL_DSP_GETODELAY
: {
1012 debug(__FILE__
": SNDCTL_DSP_GETODELAY\n");
1014 pa_threaded_mainloop_lock(i
->mainloop
);
1020 if (!i
->stream
|| pa_stream_get_state(i
->stream
) != PA_STREAM_READY
)
1023 if (pa_stream_get_latency(i
->stream
, &usec
, NULL
) >= 0) {
1024 *(int*) argp
= pa_usec_to_bytes(usec
, &i
->sample_spec
);
1028 if (pa_context_errno(i
->context
) != PA_ERR_NODATA
) {
1029 debug(__FILE__
": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1033 pa_threaded_mainloop_wait(i
->mainloop
);
1036 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0)
1037 debug(__FILE__
": SIOCINQ failed: %s\n", strerror(errno
));
1041 pa_threaded_mainloop_unlock(i
->mainloop
);
1043 debug(__FILE__
": ODELAY: %i\n", *(int*) argp
);
1048 case SNDCTL_DSP_RESET
: {
1049 debug(__FILE__
": SNDCTL_DSP_RESET\n");
1051 pa_threaded_mainloop_lock(i
->mainloop
);
1056 pa_threaded_mainloop_unlock(i
->mainloop
);
1060 case SNDCTL_DSP_GETFMTS
: {
1061 debug(__FILE__
": SNDCTL_DSP_GETFMTS\n");
1063 *(int*) argp
= AFMT_MU_LAW
|AFMT_A_LAW
|AFMT_U8
|AFMT_S16_LE
|AFMT_S16_BE
;
1067 case SNDCTL_DSP_POST
:
1068 debug(__FILE__
": SNDCTL_DSP_POST\n");
1070 if (dsp_trigger(i
) < 0)
1074 case SNDCTL_DSP_SYNC
:
1075 debug(__FILE__
": SNDCTL_DSP_SYNC\n");
1077 if (dsp_drain(i
) < 0)
1082 case SNDCTL_DSP_GETOSPACE
: {
1083 audio_buf_info
*bi
= (audio_buf_info
*) argp
;
1087 debug(__FILE__
": SNDCTL_DSP_GETOSPACE\n");
1089 pa_threaded_mainloop_lock(i
->mainloop
);
1094 if ((k
= pa_stream_writable_size(i
->stream
)) == (size_t) -1)
1095 debug(__FILE__
": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1097 k
= i
->fragment_size
* i
->n_fragments
;
1099 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0) {
1100 debug(__FILE__
": SIOCINQ failed: %s\n", strerror(errno
));
1104 bi
->fragsize
= i
->fragment_size
;
1105 bi
->fragstotal
= i
->n_fragments
;
1106 bi
->bytes
= k
> (size_t) l
? k
- l
: 0;
1107 bi
->fragments
= bi
->bytes
/ bi
->fragsize
;
1109 pa_threaded_mainloop_unlock(i
->mainloop
);
1111 debug(__FILE__
": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi
->fragsize
, bi
->fragstotal
, bi
->bytes
, bi
->fragments
);
1117 debug(__FILE__
": unknwon ioctl 0x%08lx\n", request
);
1130 int ioctl(int fd
, unsigned long request
, ...) {
1136 debug(__FILE__
": ioctl()\n");
1138 va_start(args
, request
);
1139 argp
= va_arg(args
, void *);
1142 if (!function_enter()) {
1144 return _ioctl(fd
, request
, argp
);
1147 if (!(i
= fd_info_find(fd
))) {
1150 return _ioctl(fd
, request
, argp
);
1153 if (i
->type
== FD_INFO_MIXER
)
1154 r
= mixer_ioctl(i
, request
, argp
, &_errno
);
1156 r
= dsp_ioctl(i
, request
, argp
, &_errno
);
1171 debug(__FILE__
": close()\n");
1173 if (!function_enter()) {
1178 if (!(i
= fd_info_find(fd
))) {
1184 fd_info_remove_from_list(i
);
1192 int open64(const char *filename
, int flags
, ...) {
1196 debug(__FILE__
": open64()\n");
1198 va_start(args
, flags
);
1199 if (flags
& O_CREAT
)
1200 mode
= va_arg(args
, mode_t
);
1203 if (strcmp(filename
, "/dev/dsp") != 0 &&
1204 strcmp(filename
, "/dev/adsp") != 0 &&
1205 strcmp(filename
, "/dev/mixer") != 0) {
1207 return _open64(filename
, flags
, mode
);
1210 return open(filename
, flags
, mode
);
1213 FILE* fopen(const char *filename
, const char *mode
) {
1217 debug(__FILE__
": fopen()\n");
1219 if (strcmp(filename
, "/dev/dsp") != 0 &&
1220 strcmp(filename
, "/dev/adsp") != 0 &&
1221 strcmp(filename
, "/dev/mixer") != 0) {
1223 return _fopen(filename
, mode
);
1226 if (strcmp(mode
, "wb") != 0) {
1231 if ((fd
= open(filename
, O_WRONLY
)) < 0)
1234 if (!(f
= fdopen(fd
, "wb"))) {
1242 FILE *fopen64(const char *filename
, const char *mode
) {
1244 debug(__FILE__
": fopen64()\n");
1246 if (strcmp(filename
, "/dev/dsp") != 0 &&
1247 strcmp(filename
, "/dev/adsp") != 0 &&
1248 strcmp(filename
, "/dev/mixer") != 0) {
1249 LOAD_FOPEN64_FUNC();
1250 return _fopen64(filename
, mode
);
1253 return fopen(filename
, mode
);
1256 int fclose(FILE *f
) {
1259 debug(__FILE__
": fclose()\n");
1261 if (!function_enter()) {
1266 if (!(i
= fd_info_find(fileno(f
)))) {
1272 fd_info_remove_from_list(i
);
1274 /* Dirty trick to avoid that the fd is not freed twice, once by us
1275 * and once by the real fclose() */