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 char *client_name(char *buf
, size_t n
) {
284 if (pa_get_binary_name(p
, sizeof(p
)))
285 snprintf(buf
, n
, "oss[%s]", pa_path_get_filename(p
));
287 snprintf(buf
, n
, "oss");
292 static fd_info
* fd_info_new(fd_info_type_t type
, int *_errno
) {
294 int sfds
[2] = { -1, -1 };
297 debug(__FILE__
": fd_info_new()\n");
299 signal(SIGPIPE
, SIG_IGN
); /* Yes, ugly as hell */
301 if (!(i
= malloc(sizeof(fd_info
)))) {
306 i
->app_fd
= i
->thread_fd
= -1;
313 pthread_mutex_init(&i
->mutex
, NULL
);
316 PA_LLIST_INIT(fd_info
, i
);
320 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, sfds
) < 0) {
322 debug(__FILE__
": socket() failed: %s\n", strerror(errno
));
327 i
->thread_fd
= sfds
[1];
329 if (!(i
->mainloop
= pa_threaded_mainloop_new())) {
331 debug(__FILE__
": pa_threaded_mainloop_new() failed\n");
335 if (!(i
->context
= pa_context_new(pa_threaded_mainloop_get_api(i
->mainloop
), client_name(name
, sizeof(name
))))) {
337 debug(__FILE__
": pa_context_new() failed\n");
341 pa_context_set_state_callback(i
->context
, context_state_cb
, i
);
343 if (pa_context_connect(i
->context
, NULL
, 0, NULL
) < 0) {
344 *_errno
= ECONNREFUSED
;
345 debug(__FILE__
": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
349 pa_threaded_mainloop_lock(i
->mainloop
);
351 if (pa_threaded_mainloop_start(i
->mainloop
) < 0) {
353 debug(__FILE__
": pa_threaded_mainloop_start() failed\n");
354 goto unlock_and_fail
;
357 /* Wait until the context is ready */
358 pa_threaded_mainloop_wait(i
->mainloop
);
360 if (pa_context_get_state(i
->context
) != PA_CONTEXT_READY
) {
361 *_errno
= ECONNREFUSED
;
362 debug(__FILE__
": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
363 goto unlock_and_fail
;
366 pa_threaded_mainloop_unlock(i
->mainloop
);
371 pa_threaded_mainloop_unlock(i
->mainloop
);
381 static void fd_info_add_to_list(fd_info
*i
) {
384 pthread_mutex_lock(&fd_infos_mutex
);
385 PA_LLIST_PREPEND(fd_info
, fd_infos
, i
);
386 pthread_mutex_unlock(&fd_infos_mutex
);
391 static void fd_info_remove_from_list(fd_info
*i
) {
394 pthread_mutex_lock(&fd_infos_mutex
);
395 PA_LLIST_REMOVE(fd_info
, fd_infos
, i
);
396 pthread_mutex_unlock(&fd_infos_mutex
);
401 static fd_info
* fd_info_find(int fd
) {
404 pthread_mutex_lock(&fd_infos_mutex
);
406 for (i
= fd_infos
; i
; i
= i
->next
)
407 if (i
->app_fd
== fd
) {
412 pthread_mutex_unlock(&fd_infos_mutex
);
417 static void fix_metrics(fd_info
*i
) {
419 char t
[PA_SAMPLE_SPEC_SNPRINT_MAX
];
421 fs
= pa_frame_size(&i
->sample_spec
);
422 i
->fragment_size
= (i
->fragment_size
/fs
)*fs
;
424 if (i
->n_fragments
< 2)
427 if (i
->fragment_size
<= 0)
428 if ((i
->fragment_size
= pa_bytes_per_second(&i
->sample_spec
) / 2 / i
->n_fragments
) <= 0)
429 i
->fragment_size
= 1024;
431 debug(__FILE__
": sample spec: %s\n", pa_sample_spec_snprint(t
, sizeof(t
), &i
->sample_spec
));
432 debug(__FILE__
": fixated metrics to %i fragments, %li bytes each.\n", i
->n_fragments
, (long)i
->fragment_size
);
435 static void stream_request_cb(pa_stream
*s
, size_t length
, void *userdata
) {
436 fd_info
*i
= userdata
;
440 pa_mainloop_api
*api
;
441 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
442 api
->io_enable(i
->io_event
, PA_IO_EVENT_INPUT
);
446 static void stream_latency_update_cb(pa_stream
*s
, void *userdata
) {
447 fd_info
*i
= userdata
;
450 pa_threaded_mainloop_signal(i
->mainloop
, 0);
453 static void fd_info_shutdown(fd_info
*i
) {
457 pa_mainloop_api
*api
;
458 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
459 api
->io_free(i
->io_event
);
463 if (i
->thread_fd
>= 0) {
469 static int fd_info_copy_data(fd_info
*i
, int force
) {
475 if ((n
= pa_stream_writable_size(i
->stream
)) == (size_t) -1) {
476 debug(__FILE__
": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
480 while (n
>= i
->fragment_size
|| force
) {
484 if (!(i
->buf
= malloc(i
->fragment_size
))) {
485 debug(__FILE__
": malloc() failed.\n");
490 if ((r
= read(i
->thread_fd
, i
->buf
, i
->fragment_size
)) <= 0) {
495 debug(__FILE__
": read(): %s\n", r
== 0 ? "EOF" : strerror(errno
));
499 if (pa_stream_write(i
->stream
, i
->buf
, r
, free
, 0, PA_SEEK_RELATIVE
) < 0) {
500 debug(__FILE__
": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
506 assert(n
>= (size_t) r
);
511 pa_mainloop_api
*api
;
512 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
513 api
->io_enable(i
->io_event
, n
>= i
->fragment_size
? PA_IO_EVENT_INPUT
: 0);
519 static void stream_state_cb(pa_stream
*s
, void * userdata
) {
520 fd_info
*i
= userdata
;
523 switch (pa_stream_get_state(s
)) {
525 case PA_STREAM_READY
:
526 debug(__FILE__
": stream established.\n");
529 case PA_STREAM_FAILED
:
530 debug(__FILE__
": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
534 case PA_STREAM_TERMINATED
:
535 case PA_STREAM_UNCONNECTED
:
536 case PA_STREAM_CREATING
:
541 static int create_stream(fd_info
*i
) {
549 if (!(i
->stream
= pa_stream_new(i
->context
, "audio stream", &i
->sample_spec
, NULL
))) {
550 debug(__FILE__
": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
554 pa_stream_set_state_callback(i
->stream
, stream_state_cb
, i
);
555 pa_stream_set_write_callback(i
->stream
, stream_request_cb
, i
);
556 pa_stream_set_latency_update_callback(i
->stream
, stream_latency_update_cb
, i
);
558 memset(&attr
, 0, sizeof(attr
));
559 attr
.maxlength
= i
->fragment_size
* (i
->n_fragments
+1);
560 attr
.tlength
= i
->fragment_size
* i
->n_fragments
;
561 attr
.prebuf
= i
->fragment_size
;
562 attr
.minreq
= i
->fragment_size
;
564 if (pa_stream_connect_playback(i
->stream
, NULL
, &attr
, PA_STREAM_INTERPOLATE_TIMING
|PA_STREAM_AUTO_TIMING_UPDATE
, NULL
, NULL
) < 0) {
565 debug(__FILE__
": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
569 n
= i
->fragment_size
;
570 setsockopt(i
->app_fd
, SOL_SOCKET
, SO_SNDBUF
, &n
, sizeof(n
));
571 n
= i
->fragment_size
;
572 setsockopt(i
->thread_fd
, SOL_SOCKET
, SO_RCVBUF
, &n
, sizeof(n
));
580 static void free_stream(fd_info
*i
) {
584 pa_stream_disconnect(i
->stream
);
585 pa_stream_unref(i
->stream
);
590 static void io_event_cb(pa_mainloop_api
*api
, pa_io_event
*e
, int fd
, pa_io_event_flags_t flags
, void *userdata
) {
591 fd_info
*i
= userdata
;
593 pa_threaded_mainloop_signal(i
->mainloop
, 0);
595 if (flags
& PA_IO_EVENT_INPUT
) {
598 api
->io_enable(e
, 0);
600 if (create_stream(i
) < 0)
604 if (fd_info_copy_data(i
, 0) < 0)
608 } else if (flags
& (PA_IO_EVENT_HANGUP
|PA_IO_EVENT_ERROR
))
614 /* We can't do anything better than removing the event source */
618 static int dsp_open(int flags
, int *_errno
) {
620 pa_mainloop_api
*api
;
624 if ((flags
!= O_WRONLY
) && (flags
!= (O_WRONLY
|O_NONBLOCK
))) {
629 if (!(i
= fd_info_new(FD_INFO_PLAYBACK
, _errno
)))
632 shutdown(i
->thread_fd
, SHUT_WR
);
633 shutdown(i
->app_fd
, SHUT_RD
);
635 if ((flags
& O_NONBLOCK
) == O_NONBLOCK
) {
636 if ((f
= fcntl(i
->app_fd
, F_GETFL
)) >= 0)
637 fcntl(i
->app_fd
, F_SETFL
, f
|O_NONBLOCK
);
639 if ((f
= fcntl(i
->thread_fd
, F_GETFL
)) >= 0)
640 fcntl(i
->thread_fd
, F_SETFL
, f
|O_NONBLOCK
);
642 fcntl(i
->app_fd
, F_SETFD
, FD_CLOEXEC
);
643 fcntl(i
->thread_fd
, F_SETFD
, FD_CLOEXEC
);
645 pa_threaded_mainloop_lock(i
->mainloop
);
646 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
647 if (!(i
->io_event
= api
->io_new(api
, i
->thread_fd
, PA_IO_EVENT_INPUT
, io_event_cb
, i
)))
650 pa_threaded_mainloop_unlock(i
->mainloop
);
652 debug(__FILE__
": dsp_open() succeeded, fd=%i\n", i
->app_fd
);
654 fd_info_add_to_list(i
);
661 pa_threaded_mainloop_unlock(i
->mainloop
);
668 debug(__FILE__
": dsp_open() failed\n");
673 static int mixer_open(int flags
, int *_errno
) {
679 /* if (!(i = fd_info_new(FD_INFO_MIXER))) */
684 int open(const char *filename
, int flags
, ...) {
689 va_start(args
, flags
);
691 mode
= va_arg(args
, mode_t
);
694 if (!function_enter()) {
696 return _open(filename
, flags
, mode
);
699 debug(__FILE__
": open()\n");
701 if (strcmp(filename
, "/dev/dsp") == 0 || strcmp(filename
, "/dev/adsp") == 0) {
702 r
= dsp_open(flags
, &_errno
);
703 } else if (strcmp(filename
, "/dev/mixer") == 0) {
704 r
= mixer_open(flags
, &_errno
);
708 return _open(filename
, flags
, mode
);
719 static int mixer_ioctl(fd_info
*i
, unsigned long request
, void*argp
, int *_errno
) {
724 static int map_format(int *fmt
, pa_sample_spec
*ss
) {
728 ss
->format
= PA_SAMPLE_ULAW
;
732 ss
->format
= PA_SAMPLE_ALAW
;
739 ss
->format
= PA_SAMPLE_U8
;
746 ss
->format
= PA_SAMPLE_S16BE
;
753 ss
->format
= PA_SAMPLE_S16LE
;
757 ss
->format
= PA_SAMPLE_S16NE
;
765 static int map_format_back(pa_sample_format_t format
) {
767 case PA_SAMPLE_S16LE
: return AFMT_S16_LE
;
768 case PA_SAMPLE_S16BE
: return AFMT_S16_BE
;
769 case PA_SAMPLE_ULAW
: return AFMT_MU_LAW
;
770 case PA_SAMPLE_ALAW
: return AFMT_A_LAW
;
771 case PA_SAMPLE_U8
: return AFMT_U8
;
777 static void success_cb(pa_stream
*s
, int success
, void *userdata
) {
778 fd_info
*i
= userdata
;
783 i
->operation_success
= success
;
784 pa_threaded_mainloop_signal(i
->mainloop
, 0);
787 static int dsp_empty_socket(fd_info
*i
) {
790 /* Empty the socket */
794 if (i
->thread_fd
< 0)
797 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0) {
798 debug(__FILE__
": SIOCINQ: %s\n", strerror(errno
));
805 pa_threaded_mainloop_wait(i
->mainloop
);
811 static int dsp_drain(fd_info
*i
) {
812 pa_operation
*o
= NULL
;
818 debug(__FILE__
": Draining.\n");
820 pa_threaded_mainloop_lock(i
->mainloop
);
822 if (dsp_empty_socket(i
) < 0)
828 debug(__FILE__
": Really draining.\n");
830 if (!(o
= pa_stream_drain(i
->stream
, success_cb
, i
))) {
831 debug(__FILE__
": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
835 i
->operation_success
= 0;
836 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
837 if (!i
->stream
|| pa_stream_get_state(i
->stream
) != PA_STREAM_READY
)
840 pa_threaded_mainloop_wait(i
->mainloop
);
843 if (!i
->operation_success
) {
844 debug(__FILE__
": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i
->context
)));
853 pa_operation_unref(o
);
855 pa_threaded_mainloop_unlock(i
->mainloop
);
860 static int dsp_trigger(fd_info
*i
) {
861 pa_operation
*o
= NULL
;
864 fd_info_copy_data(i
, 1);
869 pa_threaded_mainloop_lock(i
->mainloop
);
871 if (dsp_empty_socket(i
) < 0)
874 debug(__FILE__
": Triggering.\n");
876 if (!(o
= pa_stream_trigger(i
->stream
, success_cb
, i
))) {
877 debug(__FILE__
": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
881 i
->operation_success
= 0;
882 while (!pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
883 if (!i
->stream
|| pa_stream_get_state(i
->stream
) != PA_STREAM_READY
)
886 pa_threaded_mainloop_wait(i
->mainloop
);
889 if (!i
->operation_success
) {
890 debug(__FILE__
": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
899 pa_operation_unref(o
);
901 pa_threaded_mainloop_unlock(i
->mainloop
);
906 static int dsp_ioctl(fd_info
*i
, unsigned long request
, void*argp
, int *_errno
) {
910 case SNDCTL_DSP_SETFMT
: {
911 debug(__FILE__
": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp
);
913 pa_threaded_mainloop_lock(i
->mainloop
);
915 if (*(int*) argp
== AFMT_QUERY
)
916 *(int*) argp
= map_format_back(i
->sample_spec
.format
);
918 map_format((int*) argp
, &i
->sample_spec
);
922 pa_threaded_mainloop_unlock(i
->mainloop
);
926 case SNDCTL_DSP_SPEED
: {
930 debug(__FILE__
": SNDCTL_DSP_SPEED: %i\n", *(int*) argp
);
932 pa_threaded_mainloop_lock(i
->mainloop
);
935 ss
.rate
= *(int*) argp
;
937 if ((valid
= pa_sample_spec_valid(&ss
))) {
942 pa_threaded_mainloop_unlock(i
->mainloop
);
952 case SNDCTL_DSP_STEREO
:
953 debug(__FILE__
": SNDCTL_DSP_STEREO: %i\n", *(int*) argp
);
955 pa_threaded_mainloop_lock(i
->mainloop
);
957 i
->sample_spec
.channels
= *(int*) argp
? 2 : 1;
960 pa_threaded_mainloop_unlock(i
->mainloop
);
963 case SNDCTL_DSP_CHANNELS
: {
967 debug(__FILE__
": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp
);
969 pa_threaded_mainloop_lock(i
->mainloop
);
972 ss
.channels
= *(int*) argp
;
974 if ((valid
= pa_sample_spec_valid(&ss
))) {
979 pa_threaded_mainloop_unlock(i
->mainloop
);
989 case SNDCTL_DSP_GETBLKSIZE
:
990 debug(__FILE__
": SNDCTL_DSP_GETBLKSIZE\n");
992 pa_threaded_mainloop_lock(i
->mainloop
);
995 *(int*) argp
= i
->fragment_size
;
997 pa_threaded_mainloop_unlock(i
->mainloop
);
1001 case SNDCTL_DSP_SETFRAGMENT
:
1002 debug(__FILE__
": SNDCTL_DSP_SETFRAGMENT: 0x%8x\n", *(int*) argp
);
1004 pa_threaded_mainloop_lock(i
->mainloop
);
1006 i
->fragment_size
= 1 << (*(int*) argp
);
1007 i
->n_fragments
= (*(int*) argp
) >> 16;
1011 pa_threaded_mainloop_unlock(i
->mainloop
);
1015 case SNDCTL_DSP_GETCAPS
:
1016 debug(__FILE__
": SNDCTL_DSP_CAPS\n");
1018 *(int*) argp
= DSP_CAP_MULTI
;
1021 case SNDCTL_DSP_GETODELAY
: {
1024 debug(__FILE__
": SNDCTL_DSP_GETODELAY\n");
1026 pa_threaded_mainloop_lock(i
->mainloop
);
1032 if (!i
->stream
|| pa_stream_get_state(i
->stream
) != PA_STREAM_READY
)
1035 if (pa_stream_get_latency(i
->stream
, &usec
, NULL
) >= 0) {
1036 *(int*) argp
= pa_usec_to_bytes(usec
, &i
->sample_spec
);
1040 if (pa_context_errno(i
->context
) != PA_ERR_NODATA
) {
1041 debug(__FILE__
": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1045 pa_threaded_mainloop_wait(i
->mainloop
);
1048 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0)
1049 debug(__FILE__
": SIOCINQ failed: %s\n", strerror(errno
));
1053 pa_threaded_mainloop_unlock(i
->mainloop
);
1055 debug(__FILE__
": ODELAY: %i\n", *(int*) argp
);
1060 case SNDCTL_DSP_RESET
: {
1061 debug(__FILE__
": SNDCTL_DSP_RESET\n");
1063 pa_threaded_mainloop_lock(i
->mainloop
);
1068 pa_threaded_mainloop_unlock(i
->mainloop
);
1072 case SNDCTL_DSP_GETFMTS
: {
1073 debug(__FILE__
": SNDCTL_DSP_GETFMTS\n");
1075 *(int*) argp
= AFMT_MU_LAW
|AFMT_A_LAW
|AFMT_U8
|AFMT_S16_LE
|AFMT_S16_BE
;
1079 case SNDCTL_DSP_POST
:
1080 debug(__FILE__
": SNDCTL_DSP_POST\n");
1082 if (dsp_trigger(i
) < 0)
1086 case SNDCTL_DSP_SYNC
:
1087 debug(__FILE__
": SNDCTL_DSP_SYNC\n");
1089 if (dsp_drain(i
) < 0)
1094 case SNDCTL_DSP_GETOSPACE
: {
1095 audio_buf_info
*bi
= (audio_buf_info
*) argp
;
1099 debug(__FILE__
": SNDCTL_DSP_GETOSPACE\n");
1101 pa_threaded_mainloop_lock(i
->mainloop
);
1106 if ((k
= pa_stream_writable_size(i
->stream
)) == (size_t) -1)
1107 debug(__FILE__
": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1109 k
= i
->fragment_size
* i
->n_fragments
;
1111 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0) {
1112 debug(__FILE__
": SIOCINQ failed: %s\n", strerror(errno
));
1116 bi
->fragsize
= i
->fragment_size
;
1117 bi
->fragstotal
= i
->n_fragments
;
1118 bi
->bytes
= k
> (size_t) l
? k
- l
: 0;
1119 bi
->fragments
= bi
->bytes
/ bi
->fragsize
;
1121 pa_threaded_mainloop_unlock(i
->mainloop
);
1123 debug(__FILE__
": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi
->fragsize
, bi
->fragstotal
, bi
->bytes
, bi
->fragments
);
1129 debug(__FILE__
": unknwon ioctl 0x%08lx\n", request
);
1142 int ioctl(int fd
, unsigned long request
, ...) {
1148 debug(__FILE__
": ioctl()\n");
1150 va_start(args
, request
);
1151 argp
= va_arg(args
, void *);
1154 if (!function_enter()) {
1156 return _ioctl(fd
, request
, argp
);
1159 if (!(i
= fd_info_find(fd
))) {
1162 return _ioctl(fd
, request
, argp
);
1165 if (i
->type
== FD_INFO_MIXER
)
1166 r
= mixer_ioctl(i
, request
, argp
, &_errno
);
1168 r
= dsp_ioctl(i
, request
, argp
, &_errno
);
1183 debug(__FILE__
": close()\n");
1185 if (!function_enter()) {
1190 if (!(i
= fd_info_find(fd
))) {
1196 fd_info_remove_from_list(i
);
1204 int open64(const char *filename
, int flags
, ...) {
1208 debug(__FILE__
": open64()\n");
1210 va_start(args
, flags
);
1211 if (flags
& O_CREAT
)
1212 mode
= va_arg(args
, mode_t
);
1215 if (strcmp(filename
, "/dev/dsp") != 0 &&
1216 strcmp(filename
, "/dev/adsp") != 0 &&
1217 strcmp(filename
, "/dev/mixer") != 0) {
1219 return _open64(filename
, flags
, mode
);
1222 return open(filename
, flags
, mode
);
1225 FILE* fopen(const char *filename
, const char *mode
) {
1229 debug(__FILE__
": fopen()\n");
1231 if (strcmp(filename
, "/dev/dsp") != 0 &&
1232 strcmp(filename
, "/dev/adsp") != 0 &&
1233 strcmp(filename
, "/dev/mixer") != 0) {
1235 return _fopen(filename
, mode
);
1238 if (strcmp(mode
, "wb") != 0) {
1243 if ((fd
= open(filename
, O_WRONLY
)) < 0)
1246 if (!(f
= fdopen(fd
, "wb"))) {
1254 FILE *fopen64(const char *filename
, const char *mode
) {
1256 debug(__FILE__
": fopen64()\n");
1258 if (strcmp(filename
, "/dev/dsp") != 0 &&
1259 strcmp(filename
, "/dev/adsp") != 0 &&
1260 strcmp(filename
, "/dev/mixer") != 0) {
1261 LOAD_FOPEN64_FUNC();
1262 return _fopen64(filename
, mode
);
1265 return fopen(filename
, mode
);
1268 int fclose(FILE *f
) {
1271 debug(__FILE__
": fclose()\n");
1273 if (!function_enter()) {
1278 if (!(i
= fd_info_find(fileno(f
)))) {
1284 fd_info_remove_from_list(i
);
1286 /* Dirty trick to avoid that the fd is not freed twice, once by us
1287 * and once by the real fclose() */