Improve TMPDIR handling
[pulseaudio-mirror.git] / src / utils / padsp.c
blobc8c0874da66b81250ade7e24b02cac5dd3cd44be
1 /***
2 This file is part of PulseAudio.
4 Copyright 2006 Lennart Poettering
5 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #ifdef _FILE_OFFSET_BITS
28 #undef _FILE_OFFSET_BITS
29 #endif
31 #ifndef _LARGEFILE64_SOURCE
32 #define _LARGEFILE64_SOURCE 1
33 #endif
35 #include <sys/soundcard.h>
36 #include <sys/ioctl.h>
37 #include <pthread.h>
38 #include <unistd.h>
39 #include <sys/socket.h>
40 #include <sys/stat.h>
41 #include <dlfcn.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <string.h>
45 #include <stdarg.h>
46 #include <stdio.h>
47 #include <signal.h>
49 #ifdef __linux__
50 #include <linux/sockios.h>
51 #endif
53 #include <pulse/pulseaudio.h>
54 #include <pulse/gccmacro.h>
55 #include <pulsecore/llist.h>
56 #include <pulsecore/core-util.h>
58 /* On some systems SIOCINQ isn't defined, but FIONREAD is just an alias */
59 #if !defined(SIOCINQ) && defined(FIONREAD)
60 # define SIOCINQ FIONREAD
61 #endif
63 /* make sure gcc doesn't redefine open and friends as macros */
64 #undef open
65 #undef open64
67 typedef enum {
68 FD_INFO_MIXER,
69 FD_INFO_STREAM,
70 } fd_info_type_t;
72 typedef struct fd_info fd_info;
74 struct fd_info {
75 pthread_mutex_t mutex;
76 int ref;
77 int unusable;
79 fd_info_type_t type;
80 int app_fd, thread_fd;
82 pa_sample_spec sample_spec;
83 size_t fragment_size;
84 unsigned n_fragments;
86 pa_threaded_mainloop *mainloop;
87 pa_context *context;
88 pa_stream *play_stream;
89 pa_stream *rec_stream;
90 int play_precork;
91 int rec_precork;
93 pa_io_event *io_event;
94 pa_io_event_flags_t io_flags;
96 void *buf;
97 size_t rec_offset;
99 int operation_success;
101 pa_cvolume sink_volume, source_volume;
102 uint32_t sink_index, source_index;
103 int volume_modify_count;
105 int optr_n_blocks;
107 PA_LLIST_FIELDS(fd_info);
110 static int dsp_drain(fd_info *i);
111 static void fd_info_remove_from_list(fd_info *i);
113 static pthread_mutex_t fd_infos_mutex = PTHREAD_MUTEX_INITIALIZER;
114 static pthread_mutex_t func_mutex = PTHREAD_MUTEX_INITIALIZER;
116 static PA_LLIST_HEAD(fd_info, fd_infos) = NULL;
118 static int (*_ioctl)(int, int, void*) = NULL;
119 static int (*_close)(int) = NULL;
120 static int (*_open)(const char *, int, mode_t) = NULL;
121 static FILE* (*_fopen)(const char *path, const char *mode) = NULL;
122 static int (*_stat)(const char *, struct stat *) = NULL;
123 #ifdef _STAT_VER
124 static int (*___xstat)(int, const char *, struct stat *) = NULL;
125 #endif
126 #ifdef HAVE_OPEN64
127 static int (*_open64)(const char *, int, mode_t) = NULL;
128 static FILE* (*_fopen64)(const char *path, const char *mode) = NULL;
129 static int (*_stat64)(const char *, struct stat64 *) = NULL;
130 #ifdef _STAT_VER
131 static int (*___xstat64)(int, const char *, struct stat64 *) = NULL;
132 #endif
133 #endif
134 static int (*_fclose)(FILE *f) = NULL;
135 static int (*_access)(const char *, int) = NULL;
137 /* dlsym() violates ISO C, so confide the breakage into this function to
138 * avoid warnings. */
139 typedef void (*fnptr)(void);
140 static inline fnptr dlsym_fn(void *handle, const char *symbol) {
141 return (fnptr) (long) dlsym(handle, symbol);
144 #define LOAD_IOCTL_FUNC() \
145 do { \
146 pthread_mutex_lock(&func_mutex); \
147 if (!_ioctl) \
148 _ioctl = (int (*)(int, int, void*)) dlsym_fn(RTLD_NEXT, "ioctl"); \
149 pthread_mutex_unlock(&func_mutex); \
150 } while(0)
152 #define LOAD_OPEN_FUNC() \
153 do { \
154 pthread_mutex_lock(&func_mutex); \
155 if (!_open) \
156 _open = (int (*)(const char *, int, mode_t)) dlsym_fn(RTLD_NEXT, "open"); \
157 pthread_mutex_unlock(&func_mutex); \
158 } while(0)
160 #define LOAD_OPEN64_FUNC() \
161 do { \
162 pthread_mutex_lock(&func_mutex); \
163 if (!_open64) \
164 _open64 = (int (*)(const char *, int, mode_t)) dlsym_fn(RTLD_NEXT, "open64"); \
165 pthread_mutex_unlock(&func_mutex); \
166 } while(0)
168 #define LOAD_CLOSE_FUNC() \
169 do { \
170 pthread_mutex_lock(&func_mutex); \
171 if (!_close) \
172 _close = (int (*)(int)) dlsym_fn(RTLD_NEXT, "close"); \
173 pthread_mutex_unlock(&func_mutex); \
174 } while(0)
176 #define LOAD_ACCESS_FUNC() \
177 do { \
178 pthread_mutex_lock(&func_mutex); \
179 if (!_access) \
180 _access = (int (*)(const char*, int)) dlsym_fn(RTLD_NEXT, "access"); \
181 pthread_mutex_unlock(&func_mutex); \
182 } while(0)
184 #define LOAD_STAT_FUNC() \
185 do { \
186 pthread_mutex_lock(&func_mutex); \
187 if (!_stat) \
188 _stat = (int (*)(const char *, struct stat *)) dlsym_fn(RTLD_NEXT, "stat"); \
189 pthread_mutex_unlock(&func_mutex); \
190 } while(0)
192 #define LOAD_STAT64_FUNC() \
193 do { \
194 pthread_mutex_lock(&func_mutex); \
195 if (!_stat64) \
196 _stat64 = (int (*)(const char *, struct stat64 *)) dlsym_fn(RTLD_NEXT, "stat64"); \
197 pthread_mutex_unlock(&func_mutex); \
198 } while(0)
200 #define LOAD_XSTAT_FUNC() \
201 do { \
202 pthread_mutex_lock(&func_mutex); \
203 if (!___xstat) \
204 ___xstat = (int (*)(int, const char *, struct stat *)) dlsym_fn(RTLD_NEXT, "__xstat"); \
205 pthread_mutex_unlock(&func_mutex); \
206 } while(0)
208 #define LOAD_XSTAT64_FUNC() \
209 do { \
210 pthread_mutex_lock(&func_mutex); \
211 if (!___xstat64) \
212 ___xstat64 = (int (*)(int, const char *, struct stat64 *)) dlsym_fn(RTLD_NEXT, "__xstat64"); \
213 pthread_mutex_unlock(&func_mutex); \
214 } while(0)
216 #define LOAD_FOPEN_FUNC() \
217 do { \
218 pthread_mutex_lock(&func_mutex); \
219 if (!_fopen) \
220 _fopen = (FILE* (*)(const char *, const char*)) dlsym_fn(RTLD_NEXT, "fopen"); \
221 pthread_mutex_unlock(&func_mutex); \
222 } while(0)
224 #define LOAD_FOPEN64_FUNC() \
225 do { \
226 pthread_mutex_lock(&func_mutex); \
227 if (!_fopen64) \
228 _fopen64 = (FILE* (*)(const char *, const char*)) dlsym_fn(RTLD_NEXT, "fopen64"); \
229 pthread_mutex_unlock(&func_mutex); \
230 } while(0)
232 #define LOAD_FCLOSE_FUNC() \
233 do { \
234 pthread_mutex_lock(&func_mutex); \
235 if (!_fclose) \
236 _fclose = (int (*)(FILE *)) dlsym_fn(RTLD_NEXT, "fclose"); \
237 pthread_mutex_unlock(&func_mutex); \
238 } while(0)
240 #define CONTEXT_CHECK_DEAD_GOTO(i, label) do { \
241 if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \
242 debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \
243 goto label; \
245 } while(0)
247 #define PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, label) do { \
248 if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \
249 !(i)->play_stream || pa_stream_get_state((i)->play_stream) != PA_STREAM_READY) { \
250 debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \
251 goto label; \
253 } while(0)
255 #define RECORD_STREAM_CHECK_DEAD_GOTO(i, label) do { \
256 if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \
257 !(i)->rec_stream || pa_stream_get_state((i)->rec_stream) != PA_STREAM_READY) { \
258 debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \
259 goto label; \
261 } while(0)
263 static void debug(int level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3);
265 #define DEBUG_LEVEL_ALWAYS 0
266 #define DEBUG_LEVEL_NORMAL 1
267 #define DEBUG_LEVEL_VERBOSE 2
269 static void debug(int level, const char *format, ...) {
270 va_list ap;
271 const char *dlevel_s;
272 int dlevel;
274 dlevel_s = getenv("PADSP_DEBUG");
275 if (!dlevel_s)
276 return;
278 dlevel = atoi(dlevel_s);
280 if (dlevel < level)
281 return;
283 va_start(ap, format);
284 vfprintf(stderr, format, ap);
285 va_end(ap);
288 static int padsp_disabled(void) {
289 static int *sym;
290 static int sym_resolved = 0;
292 /* If the current process has a symbol __padsp_disabled__ we use
293 * it to detect whether we should enable our stuff or not. A
294 * program needs to be compiled with -rdynamic for this to work!
295 * The symbol must be an int containing a three bit bitmask: bit 1
296 * -> disable /dev/dsp emulation, bit 2 -> disable /dev/sndstat
297 * emulation, bit 3 -> disable /dev/mixer emulation. Hence a value
298 * of 7 disables padsp entirely. */
300 pthread_mutex_lock(&func_mutex);
301 if (!sym_resolved) {
302 sym = (int*) dlsym(RTLD_DEFAULT, "__padsp_disabled__");
303 sym_resolved = 1;
305 pthread_mutex_unlock(&func_mutex);
307 if (!sym)
308 return 0;
310 return *sym;
313 static int dsp_cloak_enable(void) {
314 if (padsp_disabled() & 1)
315 return 0;
317 if (getenv("PADSP_NO_DSP") || getenv("PULSE_INTERNAL"))
318 return 0;
320 return 1;
323 static int sndstat_cloak_enable(void) {
324 if (padsp_disabled() & 2)
325 return 0;
327 if (getenv("PADSP_NO_SNDSTAT") || getenv("PULSE_INTERNAL"))
328 return 0;
330 return 1;
333 static int mixer_cloak_enable(void) {
334 if (padsp_disabled() & 4)
335 return 0;
337 if (getenv("PADSP_NO_MIXER") || getenv("PULSE_INTERNAL"))
338 return 0;
340 return 1;
342 static pthread_key_t recursion_key;
344 static void recursion_key_alloc(void) {
345 pthread_key_create(&recursion_key, NULL);
348 static int function_enter(void) {
349 /* Avoid recursive calls */
350 static pthread_once_t recursion_key_once = PTHREAD_ONCE_INIT;
351 pthread_once(&recursion_key_once, recursion_key_alloc);
353 if (pthread_getspecific(recursion_key))
354 return 0;
356 pthread_setspecific(recursion_key, (void*) 1);
357 return 1;
360 static void function_exit(void) {
361 pthread_setspecific(recursion_key, NULL);
364 static void fd_info_free(fd_info *i) {
365 assert(i);
367 debug(DEBUG_LEVEL_NORMAL, __FILE__": freeing fd info (fd=%i)\n", i->app_fd);
369 dsp_drain(i);
371 if (i->mainloop)
372 pa_threaded_mainloop_stop(i->mainloop);
374 if (i->play_stream) {
375 pa_stream_disconnect(i->play_stream);
376 pa_stream_unref(i->play_stream);
379 if (i->rec_stream) {
380 pa_stream_disconnect(i->rec_stream);
381 pa_stream_unref(i->rec_stream);
384 if (i->context) {
385 pa_context_disconnect(i->context);
386 pa_context_unref(i->context);
389 if (i->mainloop)
390 pa_threaded_mainloop_free(i->mainloop);
392 if (i->app_fd >= 0) {
393 LOAD_CLOSE_FUNC();
394 _close(i->app_fd);
397 if (i->thread_fd >= 0) {
398 LOAD_CLOSE_FUNC();
399 _close(i->thread_fd);
402 free(i->buf);
404 pthread_mutex_destroy(&i->mutex);
405 free(i);
408 static fd_info *fd_info_ref(fd_info *i) {
409 assert(i);
411 pthread_mutex_lock(&i->mutex);
412 assert(i->ref >= 1);
413 i->ref++;
415 debug(DEBUG_LEVEL_VERBOSE, __FILE__": ref++, now %i\n", i->ref);
416 pthread_mutex_unlock(&i->mutex);
418 return i;
421 static void fd_info_unref(fd_info *i) {
422 int r;
423 pthread_mutex_lock(&i->mutex);
424 assert(i->ref >= 1);
425 r = --i->ref;
426 debug(DEBUG_LEVEL_VERBOSE, __FILE__": ref--, now %i\n", i->ref);
427 pthread_mutex_unlock(&i->mutex);
429 if (r <= 0)
430 fd_info_free(i);
433 static void context_state_cb(pa_context *c, void *userdata) {
434 fd_info *i = userdata;
435 assert(c);
437 switch (pa_context_get_state(c)) {
438 case PA_CONTEXT_READY:
439 case PA_CONTEXT_TERMINATED:
440 case PA_CONTEXT_FAILED:
441 pa_threaded_mainloop_signal(i->mainloop, 0);
442 break;
444 case PA_CONTEXT_UNCONNECTED:
445 case PA_CONTEXT_CONNECTING:
446 case PA_CONTEXT_AUTHORIZING:
447 case PA_CONTEXT_SETTING_NAME:
448 break;
452 static void reset_params(fd_info *i) {
453 assert(i);
455 i->sample_spec.format = PA_SAMPLE_U8;
456 i->sample_spec.channels = 1;
457 i->sample_spec.rate = 8000;
458 i->fragment_size = 0;
459 i->n_fragments = 0;
462 static const char *client_name(char *buf, size_t n) {
463 char *p;
464 const char *e;
466 if ((e = getenv("PADSP_CLIENT_NAME")))
467 return e;
469 if ((p = pa_get_binary_name_malloc())) {
470 snprintf(buf, n, "OSS Emulation[%s]", p);
471 pa_xfree(p);
472 } else
473 snprintf(buf, n, "OSS");
475 return buf;
478 static const char *stream_name(void) {
479 const char *e;
481 if ((e = getenv("PADSP_STREAM_NAME")))
482 return e;
484 return "Audio Stream";
487 static void atfork_prepare(void) {
488 fd_info *i;
490 debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_prepare() enter\n");
492 function_enter();
494 pthread_mutex_lock(&fd_infos_mutex);
496 for (i = fd_infos; i; i = i->next) {
497 pthread_mutex_lock(&i->mutex);
498 pa_threaded_mainloop_lock(i->mainloop);
501 pthread_mutex_lock(&func_mutex);
503 debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_prepare() exit\n");
506 static void atfork_parent(void) {
507 fd_info *i;
509 debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_parent() enter\n");
511 pthread_mutex_unlock(&func_mutex);
513 for (i = fd_infos; i; i = i->next) {
514 pa_threaded_mainloop_unlock(i->mainloop);
515 pthread_mutex_unlock(&i->mutex);
518 pthread_mutex_unlock(&fd_infos_mutex);
520 function_exit();
522 debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_parent() exit\n");
525 static void atfork_child(void) {
526 fd_info *i;
528 debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_child() enter\n");
530 /* We do only the bare minimum to get all fds closed */
531 pthread_mutex_init(&func_mutex, NULL);
532 pthread_mutex_init(&fd_infos_mutex, NULL);
534 for (i = fd_infos; i; i = i->next) {
535 pthread_mutex_init(&i->mutex, NULL);
537 if (i->context) {
538 pa_context_disconnect(i->context);
539 pa_context_unref(i->context);
540 i->context = NULL;
543 if (i->play_stream) {
544 pa_stream_unref(i->play_stream);
545 i->play_stream = NULL;
548 if (i->rec_stream) {
549 pa_stream_unref(i->rec_stream);
550 i->rec_stream = NULL;
553 if (i->app_fd >= 0) {
554 LOAD_CLOSE_FUNC();
555 _close(i->app_fd);
556 i->app_fd = -1;
559 if (i->thread_fd >= 0) {
560 LOAD_CLOSE_FUNC();
561 _close(i->thread_fd);
562 i->thread_fd = -1;
565 i->unusable = 1;
568 function_exit();
570 debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_child() exit\n");
573 static void install_atfork(void) {
574 pthread_atfork(atfork_prepare, atfork_parent, atfork_child);
577 static void stream_success_cb(pa_stream *s, int success, void *userdata) {
578 fd_info *i = userdata;
580 assert(s);
581 assert(i);
583 i->operation_success = success;
584 pa_threaded_mainloop_signal(i->mainloop, 0);
587 static void context_success_cb(pa_context *c, int success, void *userdata) {
588 fd_info *i = userdata;
590 assert(c);
591 assert(i);
593 i->operation_success = success;
594 pa_threaded_mainloop_signal(i->mainloop, 0);
597 static fd_info* fd_info_new(fd_info_type_t type, int *_errno) {
598 fd_info *i;
599 int sfds[2] = { -1, -1 };
600 char name[64];
601 static pthread_once_t install_atfork_once = PTHREAD_ONCE_INIT;
603 debug(DEBUG_LEVEL_NORMAL, __FILE__": fd_info_new()\n");
605 signal(SIGPIPE, SIG_IGN); /* Yes, ugly as hell */
607 pthread_once(&install_atfork_once, install_atfork);
609 if (!(i = malloc(sizeof(fd_info)))) {
610 *_errno = ENOMEM;
611 goto fail;
614 i->app_fd = i->thread_fd = -1;
615 i->type = type;
617 i->mainloop = NULL;
618 i->context = NULL;
619 i->play_stream = NULL;
620 i->rec_stream = NULL;
621 i->play_precork = 0;
622 i->rec_precork = 0;
623 i->io_event = NULL;
624 i->io_flags = 0;
625 pthread_mutex_init(&i->mutex, NULL);
626 i->ref = 1;
627 i->buf = NULL;
628 i->rec_offset = 0;
629 i->unusable = 0;
630 pa_cvolume_reset(&i->sink_volume, 2);
631 pa_cvolume_reset(&i->source_volume, 2);
632 i->volume_modify_count = 0;
633 i->sink_index = (uint32_t) -1;
634 i->source_index = (uint32_t) -1;
635 i->optr_n_blocks = 0;
636 PA_LLIST_INIT(fd_info, i);
638 reset_params(i);
640 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfds) < 0) {
641 *_errno = errno;
642 debug(DEBUG_LEVEL_NORMAL, __FILE__": socket() failed: %s\n", strerror(errno));
643 goto fail;
646 i->app_fd = sfds[0];
647 i->thread_fd = sfds[1];
649 if (!(i->mainloop = pa_threaded_mainloop_new())) {
650 *_errno = EIO;
651 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_threaded_mainloop_new() failed\n");
652 goto fail;
655 if (!(i->context = pa_context_new(pa_threaded_mainloop_get_api(i->mainloop), client_name(name, sizeof(name))))) {
656 *_errno = EIO;
657 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_context_new() failed\n");
658 goto fail;
661 pa_context_set_state_callback(i->context, context_state_cb, i);
663 if (pa_context_connect(i->context, NULL, 0, NULL) < 0) {
664 *_errno = ECONNREFUSED;
665 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
666 goto fail;
669 pa_threaded_mainloop_lock(i->mainloop);
671 if (pa_threaded_mainloop_start(i->mainloop) < 0) {
672 *_errno = EIO;
673 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_threaded_mainloop_start() failed\n");
674 goto unlock_and_fail;
677 /* Wait until the context is ready */
678 pa_threaded_mainloop_wait(i->mainloop);
680 if (pa_context_get_state(i->context) != PA_CONTEXT_READY) {
681 *_errno = ECONNREFUSED;
682 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
683 goto unlock_and_fail;
686 pa_threaded_mainloop_unlock(i->mainloop);
687 return i;
689 unlock_and_fail:
691 pa_threaded_mainloop_unlock(i->mainloop);
693 fail:
695 if (i)
696 fd_info_unref(i);
698 return NULL;
701 static void fd_info_add_to_list(fd_info *i) {
702 assert(i);
704 pthread_mutex_lock(&fd_infos_mutex);
705 PA_LLIST_PREPEND(fd_info, fd_infos, i);
706 pthread_mutex_unlock(&fd_infos_mutex);
708 fd_info_ref(i);
711 static void fd_info_remove_from_list(fd_info *i) {
712 assert(i);
714 pthread_mutex_lock(&fd_infos_mutex);
715 PA_LLIST_REMOVE(fd_info, fd_infos, i);
716 pthread_mutex_unlock(&fd_infos_mutex);
718 fd_info_unref(i);
721 static fd_info* fd_info_find(int fd) {
722 fd_info *i;
724 pthread_mutex_lock(&fd_infos_mutex);
726 for (i = fd_infos; i; i = i->next)
727 if (i->app_fd == fd && !i->unusable) {
728 fd_info_ref(i);
729 break;
732 pthread_mutex_unlock(&fd_infos_mutex);
734 return i;
737 static void fix_metrics(fd_info *i) {
738 size_t fs;
739 char t[PA_SAMPLE_SPEC_SNPRINT_MAX];
741 fs = pa_frame_size(&i->sample_spec);
743 /* Don't fix things more than necessary */
744 if ((i->fragment_size % fs) == 0 &&
745 i->n_fragments >= 2 &&
746 i->fragment_size > 0)
747 return;
749 i->fragment_size = (i->fragment_size/fs)*fs;
751 /* Number of fragments set? */
752 if (i->n_fragments < 2) {
753 if (i->fragment_size > 0) {
754 i->n_fragments = (unsigned) (pa_bytes_per_second(&i->sample_spec) / 2 / i->fragment_size);
755 if (i->n_fragments < 2)
756 i->n_fragments = 2;
757 } else
758 i->n_fragments = 12;
761 /* Fragment size set? */
762 if (i->fragment_size <= 0) {
763 i->fragment_size = pa_bytes_per_second(&i->sample_spec) / 2 / i->n_fragments;
764 if (i->fragment_size < 1024)
765 i->fragment_size = 1024;
768 debug(DEBUG_LEVEL_NORMAL, __FILE__": sample spec: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec));
769 debug(DEBUG_LEVEL_NORMAL, __FILE__": fixated metrics to %i fragments, %li bytes each.\n", i->n_fragments, (long)i->fragment_size);
772 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
773 fd_info *i = userdata;
774 assert(s);
776 if (i->io_event) {
777 pa_mainloop_api *api;
778 size_t n;
780 api = pa_threaded_mainloop_get_api(i->mainloop);
782 if (s == i->play_stream) {
783 n = pa_stream_writable_size(i->play_stream);
784 if (n == (size_t)-1) {
785 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n",
786 pa_strerror(pa_context_errno(i->context)));
789 if (n >= i->fragment_size)
790 i->io_flags |= PA_IO_EVENT_INPUT;
791 else
792 i->io_flags &= ~PA_IO_EVENT_INPUT;
795 if (s == i->rec_stream) {
796 n = pa_stream_readable_size(i->rec_stream);
797 if (n == (size_t)-1) {
798 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_readable_size(): %s\n",
799 pa_strerror(pa_context_errno(i->context)));
802 if (n >= i->fragment_size)
803 i->io_flags |= PA_IO_EVENT_OUTPUT;
804 else
805 i->io_flags &= ~PA_IO_EVENT_OUTPUT;
808 api->io_enable(i->io_event, i->io_flags);
812 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
813 fd_info *i = userdata;
814 assert(s);
816 pa_threaded_mainloop_signal(i->mainloop, 0);
819 static void fd_info_shutdown(fd_info *i) {
820 assert(i);
822 if (i->io_event) {
823 pa_mainloop_api *api;
824 api = pa_threaded_mainloop_get_api(i->mainloop);
825 api->io_free(i->io_event);
826 i->io_event = NULL;
827 i->io_flags = 0;
830 if (i->thread_fd >= 0) {
831 close(i->thread_fd);
832 i->thread_fd = -1;
836 static int fd_info_copy_data(fd_info *i, int force) {
837 size_t n;
839 if (!i->play_stream && !i->rec_stream)
840 return -1;
842 if ((i->play_stream) && (pa_stream_get_state(i->play_stream) == PA_STREAM_READY)) {
843 n = pa_stream_writable_size(i->play_stream);
845 if (n == (size_t)-1) {
846 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n",
847 pa_strerror(pa_context_errno(i->context)));
848 return -1;
851 while (n >= i->fragment_size || force) {
852 ssize_t r;
854 if (!i->buf) {
855 if (!(i->buf = malloc(i->fragment_size))) {
856 debug(DEBUG_LEVEL_NORMAL, __FILE__": malloc() failed.\n");
857 return -1;
861 if ((r = read(i->thread_fd, i->buf, i->fragment_size)) <= 0) {
863 if (errno == EAGAIN)
864 break;
866 debug(DEBUG_LEVEL_NORMAL, __FILE__": read(): %s\n", r == 0 ? "EOF" : strerror(errno));
867 return -1;
870 if (pa_stream_write(i->play_stream, i->buf, (size_t) r, free, 0LL, PA_SEEK_RELATIVE) < 0) {
871 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i->context)));
872 return -1;
875 i->buf = NULL;
877 assert(n >= (size_t) r);
878 n -= (size_t) r;
881 if (n >= i->fragment_size)
882 i->io_flags |= PA_IO_EVENT_INPUT;
883 else
884 i->io_flags &= ~PA_IO_EVENT_INPUT;
887 if ((i->rec_stream) && (pa_stream_get_state(i->rec_stream) == PA_STREAM_READY)) {
888 n = pa_stream_readable_size(i->rec_stream);
890 if (n == (size_t)-1) {
891 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_readable_size(): %s\n",
892 pa_strerror(pa_context_errno(i->context)));
893 return -1;
896 while (n >= i->fragment_size || force) {
897 ssize_t r;
898 const void *data;
899 const char *buf;
900 size_t len;
902 if (pa_stream_peek(i->rec_stream, &data, &len) < 0) {
903 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_peek(): %s\n", pa_strerror(pa_context_errno(i->context)));
904 return -1;
907 if (!data)
908 break;
910 buf = (const char*)data + i->rec_offset;
912 if ((r = write(i->thread_fd, buf, len - i->rec_offset)) <= 0) {
914 if (errno == EAGAIN)
915 break;
917 debug(DEBUG_LEVEL_NORMAL, __FILE__": write(): %s\n", strerror(errno));
918 return -1;
921 assert((size_t)r <= len - i->rec_offset);
922 i->rec_offset += (size_t) r;
924 if (i->rec_offset == len) {
925 if (pa_stream_drop(i->rec_stream) < 0) {
926 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drop(): %s\n", pa_strerror(pa_context_errno(i->context)));
927 return -1;
929 i->rec_offset = 0;
932 assert(n >= (size_t) r);
933 n -= (size_t) r;
936 if (n >= i->fragment_size)
937 i->io_flags |= PA_IO_EVENT_OUTPUT;
938 else
939 i->io_flags &= ~PA_IO_EVENT_OUTPUT;
942 if (i->io_event) {
943 pa_mainloop_api *api;
945 api = pa_threaded_mainloop_get_api(i->mainloop);
946 api->io_enable(i->io_event, i->io_flags);
949 /* So, we emptied the socket now, let's tell dsp_empty_socket()
950 * about this */
951 pa_threaded_mainloop_signal(i->mainloop, 0);
953 return 0;
956 static void stream_state_cb(pa_stream *s, void * userdata) {
957 fd_info *i = userdata;
958 assert(s);
960 switch (pa_stream_get_state(s)) {
962 case PA_STREAM_READY:
963 debug(DEBUG_LEVEL_NORMAL, __FILE__": stream established.\n");
964 break;
966 case PA_STREAM_FAILED:
967 if (s == i->play_stream) {
968 debug(DEBUG_LEVEL_NORMAL,
969 __FILE__": pa_stream_connect_playback() failed: %s\n",
970 pa_strerror(pa_context_errno(i->context)));
971 pa_stream_unref(i->play_stream);
972 i->play_stream = NULL;
973 } else if (s == i->rec_stream) {
974 debug(DEBUG_LEVEL_NORMAL,
975 __FILE__": pa_stream_connect_record() failed: %s\n",
976 pa_strerror(pa_context_errno(i->context)));
977 pa_stream_unref(i->rec_stream);
978 i->rec_stream = NULL;
980 fd_info_shutdown(i);
981 break;
983 case PA_STREAM_TERMINATED:
984 case PA_STREAM_UNCONNECTED:
985 case PA_STREAM_CREATING:
986 break;
990 static int create_playback_stream(fd_info *i) {
991 pa_buffer_attr attr;
992 int n, flags;
994 assert(i);
996 fix_metrics(i);
998 if (!(i->play_stream = pa_stream_new(i->context, stream_name(), &i->sample_spec, NULL))) {
999 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
1000 goto fail;
1003 pa_stream_set_state_callback(i->play_stream, stream_state_cb, i);
1004 pa_stream_set_write_callback(i->play_stream, stream_request_cb, i);
1005 pa_stream_set_latency_update_callback(i->play_stream, stream_latency_update_cb, i);
1007 memset(&attr, 0, sizeof(attr));
1008 attr.maxlength = (uint32_t) (i->fragment_size * (i->n_fragments+1));
1009 attr.tlength = (uint32_t) (i->fragment_size * i->n_fragments);
1010 attr.prebuf = (uint32_t) i->fragment_size;
1011 attr.minreq = (uint32_t) i->fragment_size;
1013 flags = PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_EARLY_REQUESTS;
1014 if (i->play_precork) {
1015 flags |= PA_STREAM_START_CORKED;
1016 debug(DEBUG_LEVEL_NORMAL, __FILE__": creating stream corked\n");
1018 if (pa_stream_connect_playback(i->play_stream, NULL, &attr, flags, NULL, NULL) < 0) {
1019 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
1020 goto fail;
1023 n = (int) i->fragment_size;
1024 setsockopt(i->app_fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n));
1025 n = (int) i->fragment_size;
1026 setsockopt(i->thread_fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));
1028 return 0;
1030 fail:
1031 return -1;
1034 static int create_record_stream(fd_info *i) {
1035 pa_buffer_attr attr;
1036 int n, flags;
1038 assert(i);
1040 fix_metrics(i);
1042 if (!(i->rec_stream = pa_stream_new(i->context, stream_name(), &i->sample_spec, NULL))) {
1043 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
1044 goto fail;
1047 pa_stream_set_state_callback(i->rec_stream, stream_state_cb, i);
1048 pa_stream_set_read_callback(i->rec_stream, stream_request_cb, i);
1049 pa_stream_set_latency_update_callback(i->rec_stream, stream_latency_update_cb, i);
1051 memset(&attr, 0, sizeof(attr));
1052 attr.maxlength = (uint32_t) (i->fragment_size * (i->n_fragments+1));
1053 attr.fragsize = (uint32_t) i->fragment_size;
1055 flags = PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE;
1056 if (i->rec_precork) {
1057 flags |= PA_STREAM_START_CORKED;
1058 debug(DEBUG_LEVEL_NORMAL, __FILE__": creating stream corked\n");
1060 if (pa_stream_connect_record(i->rec_stream, NULL, &attr, flags) < 0) {
1061 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
1062 goto fail;
1065 n = (int) i->fragment_size;
1066 setsockopt(i->app_fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));
1067 n = (int) i->fragment_size;
1068 setsockopt(i->thread_fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n));
1070 return 0;
1072 fail:
1073 return -1;
1076 static void free_streams(fd_info *i) {
1077 assert(i);
1079 if (i->play_stream) {
1080 pa_stream_disconnect(i->play_stream);
1081 pa_stream_unref(i->play_stream);
1082 i->play_stream = NULL;
1083 i->io_flags |= PA_IO_EVENT_INPUT;
1086 if (i->rec_stream) {
1087 pa_stream_disconnect(i->rec_stream);
1088 pa_stream_unref(i->rec_stream);
1089 i->rec_stream = NULL;
1090 i->io_flags |= PA_IO_EVENT_OUTPUT;
1093 if (i->io_event) {
1094 pa_mainloop_api *api;
1096 api = pa_threaded_mainloop_get_api(i->mainloop);
1097 api->io_enable(i->io_event, i->io_flags);
1101 static void io_event_cb(pa_mainloop_api *api, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) {
1102 fd_info *i = userdata;
1104 pa_threaded_mainloop_signal(i->mainloop, 0);
1106 if (flags & PA_IO_EVENT_INPUT) {
1108 if (!i->play_stream) {
1109 if (create_playback_stream(i) < 0)
1110 goto fail;
1111 } else {
1112 if (fd_info_copy_data(i, 0) < 0)
1113 goto fail;
1116 } else if (flags & PA_IO_EVENT_OUTPUT) {
1118 if (!i->rec_stream) {
1119 if (create_record_stream(i) < 0)
1120 goto fail;
1121 } else {
1122 if (fd_info_copy_data(i, 0) < 0)
1123 goto fail;
1126 } else if (flags & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR))
1127 goto fail;
1129 return;
1131 fail:
1132 /* We can't do anything better than removing the event source */
1133 fd_info_shutdown(i);
1136 static int dsp_open(int flags, int *_errno) {
1137 fd_info *i;
1138 pa_mainloop_api *api;
1139 int ret;
1140 int f;
1142 debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open()\n");
1144 if (!(i = fd_info_new(FD_INFO_STREAM, _errno)))
1145 return -1;
1147 if ((flags & O_NONBLOCK) == O_NONBLOCK) {
1148 if ((f = fcntl(i->app_fd, F_GETFL)) >= 0)
1149 fcntl(i->app_fd, F_SETFL, f|O_NONBLOCK);
1151 if ((f = fcntl(i->thread_fd, F_GETFL)) >= 0)
1152 fcntl(i->thread_fd, F_SETFL, f|O_NONBLOCK);
1154 fcntl(i->app_fd, F_SETFD, FD_CLOEXEC);
1155 fcntl(i->thread_fd, F_SETFD, FD_CLOEXEC);
1157 pa_threaded_mainloop_lock(i->mainloop);
1158 api = pa_threaded_mainloop_get_api(i->mainloop);
1160 switch (flags & O_ACCMODE) {
1161 case O_RDONLY:
1162 i->io_flags = PA_IO_EVENT_OUTPUT;
1163 shutdown(i->thread_fd, SHUT_RD);
1164 shutdown(i->app_fd, SHUT_WR);
1165 break;
1166 case O_WRONLY:
1167 i->io_flags = PA_IO_EVENT_INPUT;
1168 shutdown(i->thread_fd, SHUT_WR);
1169 shutdown(i->app_fd, SHUT_RD);
1170 break;
1171 case O_RDWR:
1172 i->io_flags = PA_IO_EVENT_INPUT | PA_IO_EVENT_OUTPUT;
1173 break;
1174 default:
1175 return -1;
1178 if (!(i->io_event = api->io_new(api, i->thread_fd, i->io_flags, io_event_cb, i)))
1179 goto fail;
1181 pa_threaded_mainloop_unlock(i->mainloop);
1183 debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open() succeeded, fd=%i\n", i->app_fd);
1185 fd_info_add_to_list(i);
1186 ret = i->app_fd;
1187 fd_info_unref(i);
1189 return ret;
1191 fail:
1192 pa_threaded_mainloop_unlock(i->mainloop);
1194 if (i)
1195 fd_info_unref(i);
1197 *_errno = EIO;
1199 debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open() failed\n");
1201 return -1;
1204 static void sink_info_cb(pa_context *context, const pa_sink_info *si, int eol, void *userdata) {
1205 fd_info *i = userdata;
1207 if (!si || eol < 0) {
1208 i->operation_success = 0;
1209 pa_threaded_mainloop_signal(i->mainloop, 0);
1210 return;
1213 if (eol)
1214 return;
1216 if (!pa_cvolume_equal(&i->sink_volume, &si->volume))
1217 i->volume_modify_count++;
1219 i->sink_volume = si->volume;
1220 i->sink_index = si->index;
1222 i->operation_success = 1;
1223 pa_threaded_mainloop_signal(i->mainloop, 0);
1226 static void source_info_cb(pa_context *context, const pa_source_info *si, int eol, void *userdata) {
1227 fd_info *i = userdata;
1229 if (!si || eol < 0) {
1230 i->operation_success = 0;
1231 pa_threaded_mainloop_signal(i->mainloop, 0);
1232 return;
1235 if (eol)
1236 return;
1238 if (!pa_cvolume_equal(&i->source_volume, &si->volume))
1239 i->volume_modify_count++;
1241 i->source_volume = si->volume;
1242 i->source_index = si->index;
1244 i->operation_success = 1;
1245 pa_threaded_mainloop_signal(i->mainloop, 0);
1248 static void subscribe_cb(pa_context *context, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
1249 fd_info *i = userdata;
1250 pa_operation *o = NULL;
1252 if (i->sink_index != idx)
1253 return;
1255 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
1256 return;
1258 if (!(o = pa_context_get_sink_info_by_index(i->context, i->sink_index, sink_info_cb, i))) {
1259 debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context)));
1260 return;
1263 pa_operation_unref(o);
1266 static int mixer_open(int flags, int *_errno) {
1267 fd_info *i;
1268 pa_operation *o = NULL;
1269 int ret;
1271 debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open()\n");
1273 if (!(i = fd_info_new(FD_INFO_MIXER, _errno)))
1274 return -1;
1276 pa_threaded_mainloop_lock(i->mainloop);
1278 pa_context_set_subscribe_callback(i->context, subscribe_cb, i);
1280 if (!(o = pa_context_subscribe(i->context, PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE, context_success_cb, i))) {
1281 debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context)));
1282 *_errno = EIO;
1283 goto fail;
1286 i->operation_success = 0;
1287 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1288 pa_threaded_mainloop_wait(i->mainloop);
1289 CONTEXT_CHECK_DEAD_GOTO(i, fail);
1292 pa_operation_unref(o);
1293 o = NULL;
1295 if (!i->operation_success) {
1296 debug(DEBUG_LEVEL_NORMAL, __FILE__":Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context)));
1297 *_errno = EIO;
1298 goto fail;
1301 /* Get sink info */
1303 if (!(o = pa_context_get_sink_info_by_name(i->context, NULL, sink_info_cb, i))) {
1304 debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context)));
1305 *_errno = EIO;
1306 goto fail;
1309 i->operation_success = 0;
1310 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1311 pa_threaded_mainloop_wait(i->mainloop);
1312 CONTEXT_CHECK_DEAD_GOTO(i, fail);
1315 pa_operation_unref(o);
1316 o = NULL;
1318 if (!i->operation_success) {
1319 debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context)));
1320 *_errno = EIO;
1321 goto fail;
1324 /* Get source info */
1326 if (!(o = pa_context_get_source_info_by_name(i->context, NULL, source_info_cb, i))) {
1327 debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get source info: %s", pa_strerror(pa_context_errno(i->context)));
1328 *_errno = EIO;
1329 goto fail;
1332 i->operation_success = 0;
1333 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1334 pa_threaded_mainloop_wait(i->mainloop);
1335 CONTEXT_CHECK_DEAD_GOTO(i, fail);
1338 pa_operation_unref(o);
1339 o = NULL;
1341 if (!i->operation_success) {
1342 debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get source info: %s", pa_strerror(pa_context_errno(i->context)));
1343 *_errno = EIO;
1344 goto fail;
1347 pa_threaded_mainloop_unlock(i->mainloop);
1349 debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open() succeeded, fd=%i\n", i->app_fd);
1351 fd_info_add_to_list(i);
1352 ret = i->app_fd;
1353 fd_info_unref(i);
1355 return ret;
1357 fail:
1358 if (o)
1359 pa_operation_unref(o);
1361 pa_threaded_mainloop_unlock(i->mainloop);
1363 if (i)
1364 fd_info_unref(i);
1366 *_errno = EIO;
1368 debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open() failed\n");
1370 return -1;
1373 static int sndstat_open(int flags, int *_errno) {
1374 static const char sndstat[] =
1375 "Sound Driver:3.8.1a-980706 (PulseAudio Virtual OSS)\n"
1376 "Kernel: POSIX\n"
1377 "Config options: 0\n"
1378 "\n"
1379 "Installed drivers:\n"
1380 "Type 255: PulseAudio Virtual OSS\n"
1381 "\n"
1382 "Card config:\n"
1383 "PulseAudio Virtual OSS\n"
1384 "\n"
1385 "Audio devices:\n"
1386 "0: PulseAudio Virtual OSS\n"
1387 "\n"
1388 "Synth devices: NOT ENABLED IN CONFIG\n"
1389 "\n"
1390 "Midi devices:\n"
1391 "\n"
1392 "Timers:\n"
1393 "\n"
1394 "Mixers:\n"
1395 "0: PulseAudio Virtual OSS\n";
1397 char *fn;
1398 mode_t u;
1399 int fd = -1;
1400 int e;
1401 const char *tmpdir;
1403 if (!(tmpdir = getenv("TMPDIR")))
1404 if (!(tmpdir = getenv("TMP")))
1405 if (!(tmpdir = getenv("TEMP")))
1406 tmpdir = getenv("TEMPDIR");
1408 if (!tmpdir || !pa_is_path_absolute(tmpdir))
1409 tmpdir = "/tmp";
1411 fn = pa_sprintf_malloc("%s" PA_PATH_SEP "padsp-sndstat-XXXXXX", tmpdir);
1413 debug(DEBUG_LEVEL_NORMAL, __FILE__": sndstat_open()\n");
1415 if (flags != O_RDONLY
1416 #ifdef O_LARGEFILE
1417 && flags != (O_RDONLY|O_LARGEFILE)
1418 #endif
1420 *_errno = EACCES;
1421 debug(DEBUG_LEVEL_NORMAL, __FILE__": bad access!\n");
1422 goto fail;
1425 u = umask(0077);
1426 fd = mkstemp(fn);
1427 e = errno;
1428 umask(u);
1430 if (fd < 0) {
1431 *_errno = e;
1432 debug(DEBUG_LEVEL_NORMAL, __FILE__": mkstemp() failed: %s\n", strerror(errno));
1433 goto fail;
1436 unlink(fn);
1437 pa_xfree(fn);
1439 if (write(fd, sndstat, sizeof(sndstat) -1) != sizeof(sndstat)-1) {
1440 *_errno = errno;
1441 debug(DEBUG_LEVEL_NORMAL, __FILE__": write() failed: %s\n", strerror(errno));
1442 goto fail;
1445 if (lseek(fd, SEEK_SET, 0) < 0) {
1446 *_errno = errno;
1447 debug(DEBUG_LEVEL_NORMAL, __FILE__": lseek() failed: %s\n", strerror(errno));
1448 goto fail;
1451 return fd;
1453 fail:
1454 pa_xfree(fn);
1455 if (fd >= 0)
1456 close(fd);
1457 return -1;
1460 static int real_open(const char *filename, int flags, mode_t mode) {
1461 int r, _errno = 0;
1463 debug(DEBUG_LEVEL_VERBOSE, __FILE__": open(%s)\n", filename?filename:"NULL");
1465 if (!function_enter()) {
1466 LOAD_OPEN_FUNC();
1467 return _open(filename, flags, mode);
1470 if (filename && dsp_cloak_enable() && (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0))
1471 r = dsp_open(flags, &_errno);
1472 else if (filename && mixer_cloak_enable() && strcmp(filename, "/dev/mixer") == 0)
1473 r = mixer_open(flags, &_errno);
1474 else if (filename && sndstat_cloak_enable() && strcmp(filename, "/dev/sndstat") == 0)
1475 r = sndstat_open(flags, &_errno);
1476 else {
1477 function_exit();
1478 LOAD_OPEN_FUNC();
1479 return _open(filename, flags, mode);
1482 function_exit();
1484 if (_errno)
1485 errno = _errno;
1487 return r;
1490 int open(const char *filename, int flags, ...) {
1491 va_list args;
1492 mode_t mode = 0;
1494 if (flags & O_CREAT) {
1495 va_start(args, flags);
1496 if (sizeof(mode_t) < sizeof(int))
1497 mode = (mode_t) va_arg(args, int);
1498 else
1499 mode = va_arg(args, mode_t);
1500 va_end(args);
1503 return real_open(filename, flags, mode);
1506 static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) {
1507 int ret = -1;
1509 switch (request) {
1510 case SOUND_MIXER_READ_DEVMASK :
1511 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_DEVMASK\n");
1513 *(int*) argp = SOUND_MASK_PCM | SOUND_MASK_IGAIN;
1514 break;
1516 case SOUND_MIXER_READ_RECMASK :
1517 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_RECMASK\n");
1519 *(int*) argp = SOUND_MASK_IGAIN;
1520 break;
1522 case SOUND_MIXER_READ_STEREODEVS:
1523 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_STEREODEVS\n");
1525 pa_threaded_mainloop_lock(i->mainloop);
1526 *(int*) argp = 0;
1527 if (i->sink_volume.channels > 1)
1528 *(int*) argp |= SOUND_MASK_PCM;
1529 if (i->source_volume.channels > 1)
1530 *(int*) argp |= SOUND_MASK_IGAIN;
1531 pa_threaded_mainloop_unlock(i->mainloop);
1533 break;
1535 case SOUND_MIXER_READ_RECSRC:
1536 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_RECSRC\n");
1538 *(int*) argp = SOUND_MASK_IGAIN;
1539 break;
1541 case SOUND_MIXER_WRITE_RECSRC:
1542 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_RECSRC\n");
1543 break;
1545 case SOUND_MIXER_READ_CAPS:
1546 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_CAPS\n");
1548 *(int*) argp = 0;
1549 break;
1551 case SOUND_MIXER_READ_PCM:
1552 case SOUND_MIXER_READ_IGAIN: {
1553 pa_cvolume *v;
1555 if (request == SOUND_MIXER_READ_PCM)
1556 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_PCM\n");
1557 else
1558 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_IGAIN\n");
1560 pa_threaded_mainloop_lock(i->mainloop);
1562 if (request == SOUND_MIXER_READ_PCM)
1563 v = &i->sink_volume;
1564 else
1565 v = &i->source_volume;
1567 *(int*) argp =
1568 ((v->values[0]*100/PA_VOLUME_NORM)) |
1569 ((v->values[v->channels > 1 ? 1 : 0]*100/PA_VOLUME_NORM) << 8);
1571 pa_threaded_mainloop_unlock(i->mainloop);
1573 break;
1576 case SOUND_MIXER_WRITE_PCM:
1577 case SOUND_MIXER_WRITE_IGAIN: {
1578 pa_cvolume v, *pv;
1580 if (request == SOUND_MIXER_WRITE_PCM)
1581 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_PCM\n");
1582 else
1583 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_IGAIN\n");
1585 pa_threaded_mainloop_lock(i->mainloop);
1587 if (request == SOUND_MIXER_WRITE_PCM) {
1588 v = i->sink_volume;
1589 pv = &i->sink_volume;
1590 } else {
1591 v = i->source_volume;
1592 pv = &i->source_volume;
1595 pv->values[0] = ((*(int*) argp & 0xFF)*PA_VOLUME_NORM)/100;
1596 pv->values[1] = ((*(int*) argp >> 8)*PA_VOLUME_NORM)/100;
1598 if (!pa_cvolume_equal(pv, &v)) {
1599 pa_operation *o;
1601 if (request == SOUND_MIXER_WRITE_PCM)
1602 o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, pv, context_success_cb, i);
1603 else
1604 o = pa_context_set_source_volume_by_index(i->context, i->source_index, pv, context_success_cb, i);
1606 if (!o)
1607 debug(DEBUG_LEVEL_NORMAL, __FILE__":Failed set volume: %s", pa_strerror(pa_context_errno(i->context)));
1608 else {
1610 i->operation_success = 0;
1611 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1612 CONTEXT_CHECK_DEAD_GOTO(i, exit_loop);
1614 pa_threaded_mainloop_wait(i->mainloop);
1616 exit_loop:
1618 if (!i->operation_success)
1619 debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to set volume: %s\n", pa_strerror(pa_context_errno(i->context)));
1621 pa_operation_unref(o);
1624 /* We don't wait for completion here */
1625 i->volume_modify_count++;
1628 pa_threaded_mainloop_unlock(i->mainloop);
1630 break;
1633 case SOUND_MIXER_INFO: {
1634 mixer_info *mi = argp;
1636 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_INFO\n");
1638 memset(mi, 0, sizeof(mixer_info));
1639 strncpy(mi->id, "PULSEAUDIO", sizeof(mi->id));
1640 strncpy(mi->name, "PulseAudio Virtual OSS", sizeof(mi->name));
1641 pa_threaded_mainloop_lock(i->mainloop);
1642 mi->modify_counter = i->volume_modify_count;
1643 pa_threaded_mainloop_unlock(i->mainloop);
1644 break;
1647 default:
1648 debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request);
1650 *_errno = EINVAL;
1651 goto fail;
1654 ret = 0;
1656 fail:
1658 return ret;
1661 static int map_format(int *fmt, pa_sample_spec *ss) {
1663 switch (*fmt) {
1664 case AFMT_MU_LAW:
1665 ss->format = PA_SAMPLE_ULAW;
1666 break;
1668 case AFMT_A_LAW:
1669 ss->format = PA_SAMPLE_ALAW;
1670 break;
1672 case AFMT_S8:
1673 *fmt = AFMT_U8;
1674 /* fall through */
1675 case AFMT_U8:
1676 ss->format = PA_SAMPLE_U8;
1677 break;
1679 case AFMT_U16_BE:
1680 *fmt = AFMT_S16_BE;
1681 /* fall through */
1682 case AFMT_S16_BE:
1683 ss->format = PA_SAMPLE_S16BE;
1684 break;
1686 case AFMT_U16_LE:
1687 *fmt = AFMT_S16_LE;
1688 /* fall through */
1689 case AFMT_S16_LE:
1690 ss->format = PA_SAMPLE_S16LE;
1691 break;
1693 default:
1694 ss->format = PA_SAMPLE_S16NE;
1695 *fmt = AFMT_S16_NE;
1696 break;
1699 return 0;
1702 static int map_format_back(pa_sample_format_t format) {
1703 switch (format) {
1704 case PA_SAMPLE_S16LE: return AFMT_S16_LE;
1705 case PA_SAMPLE_S16BE: return AFMT_S16_BE;
1706 case PA_SAMPLE_ULAW: return AFMT_MU_LAW;
1707 case PA_SAMPLE_ALAW: return AFMT_A_LAW;
1708 case PA_SAMPLE_U8: return AFMT_U8;
1709 default:
1710 abort();
1714 static int dsp_flush_fd(int fd) {
1715 #ifdef SIOCINQ
1716 int l;
1718 if (ioctl(fd, SIOCINQ, &l) < 0) {
1719 debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ: %s\n", strerror(errno));
1720 return -1;
1723 while (l > 0) {
1724 char buf[1024];
1725 size_t k;
1727 k = (size_t) l > sizeof(buf) ? sizeof(buf) : (size_t) l;
1728 if (read(fd, buf, k) < 0)
1729 debug(DEBUG_LEVEL_NORMAL, __FILE__": read(): %s\n", strerror(errno));
1730 l -= k;
1733 return 0;
1734 #else
1735 # warning "Your platform does not support SIOCINQ, something might not work as intended."
1736 return 0;
1737 #endif
1740 static int dsp_flush_socket(fd_info *i) {
1741 int res = 0;
1743 if ((i->thread_fd < 0) && (i->app_fd < 0))
1744 return -1;
1746 if (i->thread_fd >= 0)
1747 res = dsp_flush_fd(i->thread_fd);
1749 if (res < 0)
1750 return res;
1752 if (i->app_fd >= 0)
1753 res = dsp_flush_fd(i->app_fd);
1755 if (res < 0)
1756 return res;
1758 return 0;
1761 static int dsp_empty_socket(fd_info *i) {
1762 #ifdef SIOCINQ
1763 int ret = -1;
1765 /* Empty the socket */
1766 for (;;) {
1767 int l;
1769 if (i->thread_fd < 0)
1770 break;
1772 if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) {
1773 debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ: %s\n", strerror(errno));
1774 break;
1777 if (!l) {
1778 ret = 0;
1779 break;
1782 pa_threaded_mainloop_wait(i->mainloop);
1785 return ret;
1786 #else
1787 # warning "Your platform does not support SIOCINQ, something might not work as intended."
1788 return 0;
1789 #endif
1792 static int dsp_drain(fd_info *i) {
1793 pa_operation *o = NULL;
1794 int r = -1;
1796 if (!i->mainloop)
1797 return 0;
1799 debug(DEBUG_LEVEL_NORMAL, __FILE__": Draining.\n");
1801 pa_threaded_mainloop_lock(i->mainloop);
1803 if (dsp_empty_socket(i) < 0)
1804 goto fail;
1806 if (!i->play_stream)
1807 goto fail;
1809 debug(DEBUG_LEVEL_NORMAL, __FILE__": Really draining.\n");
1811 if (!(o = pa_stream_drain(i->play_stream, stream_success_cb, i))) {
1812 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context)));
1813 goto fail;
1816 i->operation_success = 0;
1817 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1818 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail);
1820 pa_threaded_mainloop_wait(i->mainloop);
1823 if (!i->operation_success) {
1824 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i->context)));
1825 goto fail;
1828 r = 0;
1830 fail:
1832 if (o)
1833 pa_operation_unref(o);
1835 pa_threaded_mainloop_unlock(i->mainloop);
1837 return r;
1840 static int dsp_trigger(fd_info *i) {
1841 pa_operation *o = NULL;
1842 int r = -1;
1844 if (!i->play_stream)
1845 return 0;
1847 pa_threaded_mainloop_lock(i->mainloop);
1849 if (dsp_empty_socket(i) < 0)
1850 goto fail;
1852 debug(DEBUG_LEVEL_NORMAL, __FILE__": Triggering.\n");
1854 if (!(o = pa_stream_trigger(i->play_stream, stream_success_cb, i))) {
1855 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context)));
1856 goto fail;
1859 i->operation_success = 0;
1860 while (!pa_operation_get_state(o) != PA_OPERATION_DONE) {
1861 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail);
1863 pa_threaded_mainloop_wait(i->mainloop);
1866 if (!i->operation_success) {
1867 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context)));
1868 goto fail;
1871 r = 0;
1873 fail:
1875 if (o)
1876 pa_operation_unref(o);
1878 pa_threaded_mainloop_unlock(i->mainloop);
1880 return r;
1883 static int dsp_cork(fd_info *i, pa_stream *s, int b) {
1884 pa_operation *o = NULL;
1885 int r = -1;
1887 pa_threaded_mainloop_lock(i->mainloop);
1889 if (!(o = pa_stream_cork(s, b, stream_success_cb, i))) {
1890 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_cork(): %s\n", pa_strerror(pa_context_errno(i->context)));
1891 goto fail;
1894 i->operation_success = 0;
1895 while (!pa_operation_get_state(o) != PA_OPERATION_DONE) {
1896 if (s == i->play_stream)
1897 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail);
1898 else if (s == i->rec_stream)
1899 RECORD_STREAM_CHECK_DEAD_GOTO(i, fail);
1901 pa_threaded_mainloop_wait(i->mainloop);
1904 if (!i->operation_success) {
1905 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_cork(): %s\n", pa_strerror(pa_context_errno(i->context)));
1906 goto fail;
1909 r = 0;
1911 fail:
1913 if (o)
1914 pa_operation_unref(o);
1916 pa_threaded_mainloop_unlock(i->mainloop);
1918 return r;
1921 static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) {
1922 int ret = -1;
1924 if (i->thread_fd == -1) {
1926 * We've encountered some fatal error and are just waiting
1927 * for a close.
1929 debug(DEBUG_LEVEL_NORMAL, __FILE__": got ioctl 0x%08lx in fatal error state\n", request);
1930 *_errno = EIO;
1931 return -1;
1934 switch (request) {
1935 case SNDCTL_DSP_SETFMT: {
1936 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp);
1938 pa_threaded_mainloop_lock(i->mainloop);
1940 if (*(int*) argp == AFMT_QUERY)
1941 *(int*) argp = map_format_back(i->sample_spec.format);
1942 else {
1943 map_format((int*) argp, &i->sample_spec);
1944 free_streams(i);
1947 pa_threaded_mainloop_unlock(i->mainloop);
1948 break;
1951 case SNDCTL_DSP_SPEED: {
1952 pa_sample_spec ss;
1953 int valid;
1954 char t[256];
1956 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SPEED: %i\n", *(int*) argp);
1958 pa_threaded_mainloop_lock(i->mainloop);
1960 ss = i->sample_spec;
1961 ss.rate = *(int*) argp;
1963 if ((valid = pa_sample_spec_valid(&ss))) {
1964 i->sample_spec = ss;
1965 free_streams(i);
1968 debug(DEBUG_LEVEL_NORMAL, __FILE__": ss: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec));
1970 pa_threaded_mainloop_unlock(i->mainloop);
1972 if (!valid) {
1973 *_errno = EINVAL;
1974 goto fail;
1977 break;
1980 case SNDCTL_DSP_STEREO:
1981 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_STEREO: %i\n", *(int*) argp);
1983 pa_threaded_mainloop_lock(i->mainloop);
1985 i->sample_spec.channels = *(int*) argp ? 2 : 1;
1986 free_streams(i);
1988 pa_threaded_mainloop_unlock(i->mainloop);
1989 return 0;
1991 case SNDCTL_DSP_CHANNELS: {
1992 pa_sample_spec ss;
1993 int valid;
1995 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp);
1997 pa_threaded_mainloop_lock(i->mainloop);
1999 ss = i->sample_spec;
2000 ss.channels = *(int*) argp;
2002 if ((valid = pa_sample_spec_valid(&ss))) {
2003 i->sample_spec = ss;
2004 free_streams(i);
2007 pa_threaded_mainloop_unlock(i->mainloop);
2009 if (!valid) {
2010 *_errno = EINVAL;
2011 goto fail;
2014 break;
2017 case SNDCTL_DSP_GETBLKSIZE:
2018 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETBLKSIZE\n");
2020 pa_threaded_mainloop_lock(i->mainloop);
2022 fix_metrics(i);
2023 *(int*) argp = i->fragment_size;
2025 pa_threaded_mainloop_unlock(i->mainloop);
2027 break;
2029 case SNDCTL_DSP_SETFRAGMENT:
2030 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%08x\n", *(int*) argp);
2032 pa_threaded_mainloop_lock(i->mainloop);
2034 i->fragment_size = 1 << ((*(int*) argp) & 31);
2035 i->n_fragments = (*(int*) argp) >> 16;
2037 /* 0x7FFF means that we can set whatever we like */
2038 if (i->n_fragments == 0x7FFF)
2039 i->n_fragments = 12;
2041 free_streams(i);
2043 pa_threaded_mainloop_unlock(i->mainloop);
2045 break;
2047 case SNDCTL_DSP_GETCAPS:
2048 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CAPS\n");
2050 *(int*) argp = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER
2051 #ifdef DSP_CAP_MULTI
2052 | DSP_CAP_MULTI
2053 #endif
2055 break;
2057 case SNDCTL_DSP_GETODELAY: {
2058 int l;
2060 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETODELAY\n");
2062 pa_threaded_mainloop_lock(i->mainloop);
2064 *(int*) argp = 0;
2066 for (;;) {
2067 pa_usec_t usec;
2069 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, exit_loop);
2071 if (pa_stream_get_latency(i->play_stream, &usec, NULL) >= 0) {
2072 *(int*) argp = pa_usec_to_bytes(usec, &i->sample_spec);
2073 break;
2076 if (pa_context_errno(i->context) != PA_ERR_NODATA) {
2077 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i->context)));
2078 break;
2081 pa_threaded_mainloop_wait(i->mainloop);
2084 exit_loop:
2086 #ifdef SIOCINQ
2087 if (ioctl(i->thread_fd, SIOCINQ, &l) < 0)
2088 debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno));
2089 else
2090 *(int*) argp += l;
2091 #else
2092 # warning "Your platform does not support SIOCINQ, something might not work as intended."
2093 #endif
2095 pa_threaded_mainloop_unlock(i->mainloop);
2097 debug(DEBUG_LEVEL_NORMAL, __FILE__": ODELAY: %i\n", *(int*) argp);
2099 break;
2102 case SNDCTL_DSP_RESET: {
2103 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_RESET\n");
2105 pa_threaded_mainloop_lock(i->mainloop);
2107 free_streams(i);
2108 dsp_flush_socket(i);
2110 i->optr_n_blocks = 0;
2112 pa_threaded_mainloop_unlock(i->mainloop);
2113 break;
2116 case SNDCTL_DSP_GETFMTS: {
2117 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETFMTS\n");
2119 *(int*) argp = AFMT_MU_LAW|AFMT_A_LAW|AFMT_U8|AFMT_S16_LE|AFMT_S16_BE;
2120 break;
2123 case SNDCTL_DSP_POST:
2124 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_POST\n");
2126 if (dsp_trigger(i) < 0)
2127 *_errno = EIO;
2128 break;
2130 case SNDCTL_DSP_GETTRIGGER:
2131 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETTRIGGER\n");
2133 *(int*) argp = 0;
2134 if (!i->play_precork)
2135 *(int*) argp |= PCM_ENABLE_OUTPUT;
2136 if (!i->rec_precork)
2137 *(int*) argp |= PCM_ENABLE_INPUT;
2139 break;
2141 case SNDCTL_DSP_SETTRIGGER:
2142 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETTRIGGER: 0x%08x\n", *(int*) argp);
2144 if (!i->io_event) {
2145 *_errno = EIO;
2146 break;
2149 i->play_precork = !((*(int*) argp) & PCM_ENABLE_OUTPUT);
2151 if (i->play_stream) {
2152 if (dsp_cork(i, i->play_stream, !((*(int*) argp) & PCM_ENABLE_OUTPUT)) < 0)
2153 *_errno = EIO;
2154 if (dsp_trigger(i) < 0)
2155 *_errno = EIO;
2158 i->rec_precork = !((*(int*) argp) & PCM_ENABLE_INPUT);
2160 if (i->rec_stream) {
2161 if (dsp_cork(i, i->rec_stream, !((*(int*) argp) & PCM_ENABLE_INPUT)) < 0)
2162 *_errno = EIO;
2165 break;
2167 case SNDCTL_DSP_SYNC:
2168 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SYNC\n");
2170 if (dsp_drain(i) < 0)
2171 *_errno = EIO;
2173 break;
2175 case SNDCTL_DSP_GETOSPACE:
2176 case SNDCTL_DSP_GETISPACE: {
2177 audio_buf_info *bi = (audio_buf_info*) argp;
2178 int l = 0;
2179 size_t k = 0;
2181 if (request == SNDCTL_DSP_GETOSPACE)
2182 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETOSPACE\n");
2183 else
2184 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETISPACE\n");
2186 pa_threaded_mainloop_lock(i->mainloop);
2188 fix_metrics(i);
2190 if (request == SNDCTL_DSP_GETOSPACE) {
2191 if (i->play_stream) {
2192 if ((k = pa_stream_writable_size(i->play_stream)) == (size_t) -1)
2193 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context)));
2194 } else
2195 k = i->fragment_size * i->n_fragments;
2197 #ifdef SIOCINQ
2198 if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) {
2199 debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno));
2200 l = 0;
2202 #else
2203 # warning "Your platform does not dsp_flush_fd, something might not work as intended."
2204 #endif
2206 bi->bytes = k > (size_t) l ? k - l : 0;
2207 } else {
2208 if (i->rec_stream) {
2209 if ((k = pa_stream_readable_size(i->rec_stream)) == (size_t) -1)
2210 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_readable_size(): %s\n", pa_strerror(pa_context_errno(i->context)));
2211 } else
2212 k = 0;
2214 #ifdef SIOCINQ
2215 if (ioctl(i->app_fd, SIOCINQ, &l) < 0) {
2216 debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno));
2217 l = 0;
2219 #else
2220 # warning "Your platform does not dsp_flush_fd, something might not work as intended."
2221 #endif
2222 bi->bytes = k + l;
2225 bi->fragsize = i->fragment_size;
2226 bi->fragstotal = i->n_fragments;
2227 bi->fragments = bi->bytes / bi->fragsize;
2229 pa_threaded_mainloop_unlock(i->mainloop);
2231 debug(DEBUG_LEVEL_NORMAL, __FILE__": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi->fragsize, bi->fragstotal, bi->bytes, bi->fragments);
2233 break;
2236 case SOUND_PCM_READ_RATE:
2237 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_RATE\n");
2239 pa_threaded_mainloop_lock(i->mainloop);
2240 *(int*) argp = i->sample_spec.rate;
2241 pa_threaded_mainloop_unlock(i->mainloop);
2242 break;
2244 case SOUND_PCM_READ_CHANNELS:
2245 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_CHANNELS\n");
2247 pa_threaded_mainloop_lock(i->mainloop);
2248 *(int*) argp = i->sample_spec.channels;
2249 pa_threaded_mainloop_unlock(i->mainloop);
2250 break;
2252 case SOUND_PCM_READ_BITS:
2253 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_BITS\n");
2255 pa_threaded_mainloop_lock(i->mainloop);
2256 *(int*) argp = pa_sample_size(&i->sample_spec)*8;
2257 pa_threaded_mainloop_unlock(i->mainloop);
2258 break;
2260 case SNDCTL_DSP_GETOPTR: {
2261 count_info *info;
2263 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETOPTR\n");
2265 info = (count_info*) argp;
2266 memset(info, 0, sizeof(*info));
2268 pa_threaded_mainloop_lock(i->mainloop);
2270 for (;;) {
2271 pa_usec_t usec;
2273 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, exit_loop2);
2275 if (pa_stream_get_time(i->play_stream, &usec) >= 0) {
2276 size_t k = pa_usec_to_bytes(usec, &i->sample_spec);
2277 int m;
2279 info->bytes = (int) k;
2280 m = k / i->fragment_size;
2281 info->blocks = m - i->optr_n_blocks;
2282 i->optr_n_blocks = m;
2284 break;
2287 if (pa_context_errno(i->context) != PA_ERR_NODATA) {
2288 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i->context)));
2289 break;
2292 pa_threaded_mainloop_wait(i->mainloop);
2295 exit_loop2:
2297 pa_threaded_mainloop_unlock(i->mainloop);
2299 debug(DEBUG_LEVEL_NORMAL, __FILE__": GETOPTR bytes=%i, blocks=%i, ptr=%i\n", info->bytes, info->blocks, info->ptr);
2301 break;
2304 case SNDCTL_DSP_GETIPTR:
2305 debug(DEBUG_LEVEL_NORMAL, __FILE__": invalid ioctl SNDCTL_DSP_GETIPTR\n");
2306 goto inval;
2308 case SNDCTL_DSP_SETDUPLEX:
2309 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETDUPLEX\n");
2310 /* this is a no-op */
2311 break;
2313 default:
2314 /* Mixer ioctls are valid on /dev/dsp aswell */
2315 return mixer_ioctl(i, request, argp, _errno);
2317 inval:
2318 *_errno = EINVAL;
2319 goto fail;
2322 ret = 0;
2324 fail:
2326 return ret;
2329 #ifdef sun
2330 int ioctl(int fd, int request, ...) {
2331 #else
2332 int ioctl(int fd, unsigned long request, ...) {
2333 #endif
2334 fd_info *i;
2335 va_list args;
2336 void *argp;
2337 int r, _errno = 0;
2339 debug(DEBUG_LEVEL_VERBOSE, __FILE__": ioctl()\n");
2341 va_start(args, request);
2342 argp = va_arg(args, void *);
2343 va_end(args);
2345 if (!function_enter()) {
2346 LOAD_IOCTL_FUNC();
2347 return _ioctl(fd, request, argp);
2350 if (!(i = fd_info_find(fd))) {
2351 function_exit();
2352 LOAD_IOCTL_FUNC();
2353 return _ioctl(fd, request, argp);
2356 if (i->type == FD_INFO_MIXER)
2357 r = mixer_ioctl(i, request, argp, &_errno);
2358 else
2359 r = dsp_ioctl(i, request, argp, &_errno);
2361 fd_info_unref(i);
2363 if (_errno)
2364 errno = _errno;
2366 function_exit();
2368 return r;
2371 int close(int fd) {
2372 fd_info *i;
2374 debug(DEBUG_LEVEL_VERBOSE, __FILE__": close()\n");
2376 if (!function_enter()) {
2377 LOAD_CLOSE_FUNC();
2378 return _close(fd);
2381 if (!(i = fd_info_find(fd))) {
2382 function_exit();
2383 LOAD_CLOSE_FUNC();
2384 return _close(fd);
2387 fd_info_remove_from_list(i);
2388 fd_info_unref(i);
2390 function_exit();
2392 return 0;
2395 int access(const char *pathname, int mode) {
2397 debug(DEBUG_LEVEL_VERBOSE, __FILE__": access(%s)\n", pathname?pathname:"NULL");
2399 if (!pathname ||
2400 (strcmp(pathname, "/dev/dsp") != 0 &&
2401 strcmp(pathname, "/dev/adsp") != 0 &&
2402 strcmp(pathname, "/dev/sndstat") != 0 &&
2403 strcmp(pathname, "/dev/mixer") != 0 )) {
2404 LOAD_ACCESS_FUNC();
2405 return _access(pathname, mode);
2408 if (mode & X_OK) {
2409 debug(DEBUG_LEVEL_NORMAL, __FILE__": access(%s, %x) = EACCESS\n", pathname, mode);
2410 errno = EACCES;
2411 return -1;
2414 debug(DEBUG_LEVEL_NORMAL, __FILE__": access(%s, %x) = OK\n", pathname, mode);
2416 return 0;
2419 int stat(const char *pathname, struct stat *buf) {
2420 #ifdef HAVE_OPEN64
2421 struct stat64 parent;
2422 #else
2423 struct stat parent;
2424 #endif
2425 int ret;
2427 if (!pathname ||
2428 !buf ||
2429 ( strcmp(pathname, "/dev/dsp") != 0 &&
2430 strcmp(pathname, "/dev/adsp") != 0 &&
2431 strcmp(pathname, "/dev/sndstat") != 0 &&
2432 strcmp(pathname, "/dev/mixer") != 0 )) {
2433 debug(DEBUG_LEVEL_VERBOSE, __FILE__": stat(%s)\n", pathname?pathname:"NULL");
2434 LOAD_STAT_FUNC();
2435 return _stat(pathname, buf);
2438 debug(DEBUG_LEVEL_NORMAL, __FILE__": stat(%s)\n", pathname);
2440 #ifdef _STAT_VER
2441 #ifdef HAVE_OPEN64
2442 ret = __xstat64(_STAT_VER, "/dev", &parent);
2443 #else
2444 ret = __xstat(_STAT_VER, "/dev", &parent);
2445 #endif
2446 #else
2447 #ifdef HAVE_OPEN64
2448 ret = stat64("/dev", &parent);
2449 #else
2450 ret = stat("/dev", &parent);
2451 #endif
2452 #endif
2454 if (ret) {
2455 debug(DEBUG_LEVEL_NORMAL, __FILE__": unable to stat \"/dev\"\n");
2456 return -1;
2459 buf->st_dev = parent.st_dev;
2460 buf->st_ino = 0xDEADBEEF; /* FIXME: Can we do this in a safe way? */
2461 buf->st_mode = S_IFCHR | S_IRUSR | S_IWUSR;
2462 buf->st_nlink = 1;
2463 buf->st_uid = getuid();
2464 buf->st_gid = getgid();
2465 buf->st_rdev = 0x0E03; /* FIXME: Linux specific */
2466 buf->st_size = 0;
2467 buf->st_atime = 1181557705;
2468 buf->st_mtime = 1181557705;
2469 buf->st_ctime = 1181557705;
2470 buf->st_blksize = 1;
2471 buf->st_blocks = 0;
2473 return 0;
2476 #ifdef HAVE_OPEN64
2478 int stat64(const char *pathname, struct stat64 *buf) {
2479 struct stat oldbuf;
2480 int ret;
2482 debug(DEBUG_LEVEL_VERBOSE, __FILE__": stat64(%s)\n", pathname?pathname:"NULL");
2484 if (!pathname ||
2485 !buf ||
2486 ( strcmp(pathname, "/dev/dsp") != 0 &&
2487 strcmp(pathname, "/dev/adsp") != 0 &&
2488 strcmp(pathname, "/dev/sndstat") != 0 &&
2489 strcmp(pathname, "/dev/mixer") != 0 )) {
2490 LOAD_STAT64_FUNC();
2491 return _stat64(pathname, buf);
2494 ret = stat(pathname, &oldbuf);
2495 if (ret)
2496 return ret;
2498 buf->st_dev = oldbuf.st_dev;
2499 buf->st_ino = oldbuf.st_ino;
2500 buf->st_mode = oldbuf.st_mode;
2501 buf->st_nlink = oldbuf.st_nlink;
2502 buf->st_uid = oldbuf.st_uid;
2503 buf->st_gid = oldbuf.st_gid;
2504 buf->st_rdev = oldbuf.st_rdev;
2505 buf->st_size = oldbuf.st_size;
2506 buf->st_atime = oldbuf.st_atime;
2507 buf->st_mtime = oldbuf.st_mtime;
2508 buf->st_ctime = oldbuf.st_ctime;
2509 buf->st_blksize = oldbuf.st_blksize;
2510 buf->st_blocks = oldbuf.st_blocks;
2512 return 0;
2515 int open64(const char *filename, int flags, ...) {
2516 va_list args;
2517 mode_t mode = 0;
2519 debug(DEBUG_LEVEL_VERBOSE, __FILE__": open64(%s)\n", filename?filename:"NULL");
2521 if (flags & O_CREAT) {
2522 va_start(args, flags);
2523 if (sizeof(mode_t) < sizeof(int))
2524 mode = va_arg(args, int);
2525 else
2526 mode = va_arg(args, mode_t);
2527 va_end(args);
2530 if (!filename ||
2531 ( strcmp(filename, "/dev/dsp") != 0 &&
2532 strcmp(filename, "/dev/adsp") != 0 &&
2533 strcmp(filename, "/dev/sndstat") != 0 &&
2534 strcmp(filename, "/dev/mixer") != 0 )) {
2535 LOAD_OPEN64_FUNC();
2536 return _open64(filename, flags, mode);
2539 return real_open(filename, flags, mode);
2542 #endif
2544 #ifdef _STAT_VER
2546 int __xstat(int ver, const char *pathname, struct stat *buf) {
2547 debug(DEBUG_LEVEL_VERBOSE, __FILE__": __xstat(%s)\n", pathname?pathname:"NULL");
2549 if (!pathname ||
2550 !buf ||
2551 ( strcmp(pathname, "/dev/dsp") != 0 &&
2552 strcmp(pathname, "/dev/adsp") != 0 &&
2553 strcmp(pathname, "/dev/sndstat") != 0 &&
2554 strcmp(pathname, "/dev/mixer") != 0 )) {
2555 LOAD_XSTAT_FUNC();
2556 return ___xstat(ver, pathname, buf);
2559 if (ver != _STAT_VER) {
2560 errno = EINVAL;
2561 return -1;
2564 return stat(pathname, buf);
2567 #ifdef HAVE_OPEN64
2569 int __xstat64(int ver, const char *pathname, struct stat64 *buf) {
2570 debug(DEBUG_LEVEL_VERBOSE, __FILE__": __xstat64(%s)\n", pathname?pathname:"NULL");
2572 if (!pathname ||
2573 !buf ||
2574 ( strcmp(pathname, "/dev/dsp") != 0 &&
2575 strcmp(pathname, "/dev/adsp") != 0 &&
2576 strcmp(pathname, "/dev/sndstat") != 0 &&
2577 strcmp(pathname, "/dev/mixer") != 0 )) {
2578 LOAD_XSTAT64_FUNC();
2579 return ___xstat64(ver, pathname, buf);
2582 if (ver != _STAT_VER) {
2583 errno = EINVAL;
2584 return -1;
2587 return stat64(pathname, buf);
2590 #endif
2592 #endif
2594 FILE* fopen(const char *filename, const char *mode) {
2595 FILE *f = NULL;
2596 int fd;
2597 mode_t m;
2599 debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen(%s)\n", filename?filename:"NULL");
2601 if (!filename ||
2602 !mode ||
2603 ( strcmp(filename, "/dev/dsp") != 0 &&
2604 strcmp(filename, "/dev/adsp") != 0 &&
2605 strcmp(filename, "/dev/sndstat") != 0 &&
2606 strcmp(filename, "/dev/mixer") != 0 )) {
2607 LOAD_FOPEN_FUNC();
2608 return _fopen(filename, mode);
2611 switch (mode[0]) {
2612 case 'r':
2613 m = O_RDONLY;
2614 break;
2615 case 'w':
2616 case 'a':
2617 m = O_WRONLY;
2618 break;
2619 default:
2620 errno = EINVAL;
2621 return NULL;
2624 if ((((mode[1] == 'b') || (mode[1] == 't')) && (mode[2] == '+')) || (mode[1] == '+'))
2625 m = O_RDWR;
2627 if ((fd = real_open(filename, m, 0)) < 0)
2628 return NULL;
2630 if (!(f = fdopen(fd, mode))) {
2631 close(fd);
2632 return NULL;
2635 return f;
2638 #ifdef HAVE_OPEN64
2640 FILE *fopen64(const char *filename, const char *mode) {
2642 debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen64(%s)\n", filename?filename:"NULL");
2644 if (!filename ||
2645 !mode ||
2646 ( strcmp(filename, "/dev/dsp") != 0 &&
2647 strcmp(filename, "/dev/adsp") != 0 &&
2648 strcmp(filename, "/dev/sndstat") != 0 &&
2649 strcmp(filename, "/dev/mixer") != 0 )) {
2650 LOAD_FOPEN64_FUNC();
2651 return _fopen64(filename, mode);
2654 return fopen(filename, mode);
2657 #endif
2659 int fclose(FILE *f) {
2660 fd_info *i;
2662 debug(DEBUG_LEVEL_VERBOSE, __FILE__": fclose()\n");
2664 if (!function_enter()) {
2665 LOAD_FCLOSE_FUNC();
2666 return _fclose(f);
2669 if (!(i = fd_info_find(fileno(f)))) {
2670 function_exit();
2671 LOAD_FCLOSE_FUNC();
2672 return _fclose(f);
2675 fd_info_remove_from_list(i);
2677 /* Dirty trick to avoid that the fd is not freed twice, once by us
2678 * and once by the real fclose() */
2679 i->app_fd = -1;
2681 fd_info_unref(i);
2683 function_exit();
2685 LOAD_FCLOSE_FUNC();
2686 return _fclose(f);