]> code.delx.au - pulseaudio/blob - src/utils/padsp.c
Merge FreeBSD compatibility patch (from Flameeyes)
[pulseaudio] / src / utils / padsp.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 PulseAudio 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.
10
11 PulseAudio 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.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #ifdef _FILE_OFFSET_BITS
27 #undef _FILE_OFFSET_BITS
28 #endif
29
30 #ifndef _LARGEFILE64_SOURCE
31 #define _LARGEFILE64_SOURCE 1
32 #endif
33
34 #include <sys/soundcard.h>
35 #include <sys/ioctl.h>
36 #include <pthread.h>
37 #include <unistd.h>
38 #include <sys/socket.h>
39 #include <sys/stat.h>
40 #include <dlfcn.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <string.h>
44 #include <stdarg.h>
45 #include <stdio.h>
46 #include <signal.h>
47
48 #ifdef __linux__
49 #include <linux/sockios.h>
50 #endif
51
52 #include <pulse/pulseaudio.h>
53 #include <pulsecore/llist.h>
54 #include <pulsecore/gccmacro.h>
55
56 /* On some systems SIOCINQ isn't defined, but FIONREAD is just an alias */
57 #if !defined(SIOCINQ) && defined(FIONREAD)
58 # define SIOCINQ FIONREAD
59 #endif
60
61 typedef enum {
62 FD_INFO_MIXER,
63 FD_INFO_STREAM,
64 } fd_info_type_t;
65
66 typedef struct fd_info fd_info;
67
68 struct fd_info {
69 pthread_mutex_t mutex;
70 int ref;
71 int unusable;
72
73 fd_info_type_t type;
74 int app_fd, thread_fd;
75
76 pa_sample_spec sample_spec;
77 size_t fragment_size;
78 unsigned n_fragments;
79
80 pa_threaded_mainloop *mainloop;
81 pa_context *context;
82 pa_stream *play_stream;
83 pa_stream *rec_stream;
84
85 pa_io_event *io_event;
86 pa_io_event_flags_t io_flags;
87
88 void *buf;
89 size_t rec_offset;
90
91 int operation_success;
92
93 pa_cvolume sink_volume, source_volume;
94 uint32_t sink_index, source_index;
95 int volume_modify_count;
96
97 PA_LLIST_FIELDS(fd_info);
98 };
99
100 static int dsp_drain(fd_info *i);
101 static void fd_info_remove_from_list(fd_info *i);
102
103 static pthread_mutex_t fd_infos_mutex = PTHREAD_MUTEX_INITIALIZER;
104 static pthread_mutex_t func_mutex = PTHREAD_MUTEX_INITIALIZER;
105
106 static PA_LLIST_HEAD(fd_info, fd_infos) = NULL;
107
108 static int (*_ioctl)(int, int, void*) = NULL;
109 static int (*_close)(int) = NULL;
110 static int (*_open)(const char *, int, mode_t) = NULL;
111 static FILE* (*_fopen)(const char *path, const char *mode) = NULL;
112 #ifdef HAVE_OPEN64
113 static int (*_open64)(const char *, int, mode_t) = NULL;
114 static FILE* (*_fopen64)(const char *path, const char *mode) = NULL;
115 #endif
116 static int (*_fclose)(FILE *f) = NULL;
117 static int (*_access)(const char *, int) = NULL;
118
119 /* dlsym() violates ISO C, so confide the breakage into this function to
120 * avoid warnings. */
121 typedef void (*fnptr)(void);
122 static inline fnptr dlsym_fn(void *handle, const char *symbol) {
123 return (fnptr) (long) dlsym(handle, symbol);
124 }
125
126 #define LOAD_IOCTL_FUNC() \
127 do { \
128 pthread_mutex_lock(&func_mutex); \
129 if (!_ioctl) \
130 _ioctl = (int (*)(int, int, void*)) dlsym_fn(RTLD_NEXT, "ioctl"); \
131 pthread_mutex_unlock(&func_mutex); \
132 } while(0)
133
134 #define LOAD_OPEN_FUNC() \
135 do { \
136 pthread_mutex_lock(&func_mutex); \
137 if (!_open) \
138 _open = (int (*)(const char *, int, mode_t)) dlsym_fn(RTLD_NEXT, "open"); \
139 pthread_mutex_unlock(&func_mutex); \
140 } while(0)
141
142 #define LOAD_OPEN64_FUNC() \
143 do { \
144 pthread_mutex_lock(&func_mutex); \
145 if (!_open64) \
146 _open64 = (int (*)(const char *, int, mode_t)) dlsym_fn(RTLD_NEXT, "open64"); \
147 pthread_mutex_unlock(&func_mutex); \
148 } while(0)
149
150 #define LOAD_CLOSE_FUNC() \
151 do { \
152 pthread_mutex_lock(&func_mutex); \
153 if (!_close) \
154 _close = (int (*)(int)) dlsym_fn(RTLD_NEXT, "close"); \
155 pthread_mutex_unlock(&func_mutex); \
156 } while(0)
157
158 #define LOAD_ACCESS_FUNC() \
159 do { \
160 pthread_mutex_lock(&func_mutex); \
161 if (!_access) \
162 _access = (int (*)(const char*, int)) dlsym_fn(RTLD_NEXT, "access"); \
163 pthread_mutex_unlock(&func_mutex); \
164 } while(0)
165
166 #define LOAD_FOPEN_FUNC() \
167 do { \
168 pthread_mutex_lock(&func_mutex); \
169 if (!_fopen) \
170 _fopen = (FILE* (*)(const char *, const char*)) dlsym_fn(RTLD_NEXT, "fopen"); \
171 pthread_mutex_unlock(&func_mutex); \
172 } while(0)
173
174 #define LOAD_FOPEN64_FUNC() \
175 do { \
176 pthread_mutex_lock(&func_mutex); \
177 if (!_fopen64) \
178 _fopen64 = (FILE* (*)(const char *, const char*)) dlsym_fn(RTLD_NEXT, "fopen64"); \
179 pthread_mutex_unlock(&func_mutex); \
180 } while(0)
181
182 #define LOAD_FCLOSE_FUNC() \
183 do { \
184 pthread_mutex_lock(&func_mutex); \
185 if (!_fclose) \
186 _fclose = (int (*)(FILE *)) dlsym_fn(RTLD_NEXT, "fclose"); \
187 pthread_mutex_unlock(&func_mutex); \
188 } while(0)
189
190 #define CONTEXT_CHECK_DEAD_GOTO(i, label) do { \
191 if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \
192 debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \
193 goto label; \
194 } \
195 } while(0);
196
197 #define PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, label) do { \
198 if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \
199 !(i)->play_stream || pa_stream_get_state((i)->play_stream) != PA_STREAM_READY) { \
200 debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \
201 goto label; \
202 } \
203 } while(0);
204
205 #define RECORD_STREAM_CHECK_DEAD_GOTO(i, label) do { \
206 if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \
207 !(i)->rec_stream || pa_stream_get_state((i)->rec_stream) != PA_STREAM_READY) { \
208 debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \
209 goto label; \
210 } \
211 } while(0);
212
213 static void debug(int level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3);
214
215 #define DEBUG_LEVEL_ALWAYS 0
216 #define DEBUG_LEVEL_NORMAL 1
217 #define DEBUG_LEVEL_VERBOSE 2
218
219 static void debug(int level, const char *format, ...) {
220 va_list ap;
221 const char *dlevel_s;
222 int dlevel;
223
224 dlevel_s = getenv("PADSP_DEBUG");
225 if (!dlevel_s)
226 return;
227
228 dlevel = atoi(dlevel_s);
229
230 if (dlevel < level)
231 return;
232
233 va_start(ap, format);
234 vfprintf(stderr, format, ap);
235 va_end(ap);
236 }
237
238 static int padsp_disabled(void) {
239 static int *sym;
240 static int sym_resolved = 0;
241
242 /* If the current process has a symbol __padsp_disabled__ we use
243 * it to detect whether we should enable our stuff or not. A
244 * program needs to be compiled with -rdynamic for this to work!
245 * The symbol must be an int containing a three bit bitmask: bit 1
246 * -> disable /dev/dsp emulation, bit 2 -> disable /dev/sndstat
247 * emulation, bit 3 -> disable /dev/mixer emulation. Hence a value
248 * of 7 disables padsp entirely. */
249
250 pthread_mutex_lock(&func_mutex);
251 if (!sym_resolved) {
252 sym = (int*) dlsym(RTLD_DEFAULT, "__padsp_disabled__");
253 sym_resolved = 1;
254
255 }
256 pthread_mutex_unlock(&func_mutex);
257
258 if (!sym)
259 return 0;
260
261 return *sym;
262 }
263
264 static int dsp_cloak_enable(void) {
265 if (padsp_disabled() & 1)
266 return 0;
267
268 if (getenv("PADSP_NO_DSP"))
269 return 0;
270
271 return 1;
272 }
273
274 static int sndstat_cloak_enable(void) {
275 if (padsp_disabled() & 2)
276 return 0;
277
278 if (getenv("PADSP_NO_SNDSTAT"))
279 return 0;
280
281 return 1;
282 }
283
284 static int mixer_cloak_enable(void) {
285 if (padsp_disabled() & 4)
286 return 0;
287
288 if (getenv("PADSP_NO_MIXER"))
289 return 0;
290
291 return 1;
292 }
293 static pthread_key_t recursion_key;
294
295 static void recursion_key_alloc(void) {
296 pthread_key_create(&recursion_key, NULL);
297 }
298
299 static int function_enter(void) {
300 /* Avoid recursive calls */
301 static pthread_once_t recursion_key_once = PTHREAD_ONCE_INIT;
302 pthread_once(&recursion_key_once, recursion_key_alloc);
303
304 if (pthread_getspecific(recursion_key))
305 return 0;
306
307 pthread_setspecific(recursion_key, (void*) 1);
308 return 1;
309 }
310
311 static void function_exit(void) {
312 pthread_setspecific(recursion_key, NULL);
313 }
314
315 static void fd_info_free(fd_info *i) {
316 assert(i);
317
318 debug(DEBUG_LEVEL_NORMAL, __FILE__": freeing fd info (fd=%i)\n", i->app_fd);
319
320 dsp_drain(i);
321
322 if (i->mainloop)
323 pa_threaded_mainloop_stop(i->mainloop);
324
325 if (i->play_stream) {
326 pa_stream_disconnect(i->play_stream);
327 pa_stream_unref(i->play_stream);
328 }
329
330 if (i->rec_stream) {
331 pa_stream_disconnect(i->rec_stream);
332 pa_stream_unref(i->rec_stream);
333 }
334
335 if (i->context) {
336 pa_context_disconnect(i->context);
337 pa_context_unref(i->context);
338 }
339
340 if (i->mainloop)
341 pa_threaded_mainloop_free(i->mainloop);
342
343 if (i->app_fd >= 0) {
344 LOAD_CLOSE_FUNC();
345 _close(i->app_fd);
346 }
347
348 if (i->thread_fd >= 0) {
349 LOAD_CLOSE_FUNC();
350 _close(i->thread_fd);
351 }
352
353 free(i->buf);
354
355 pthread_mutex_destroy(&i->mutex);
356 free(i);
357 }
358
359 static fd_info *fd_info_ref(fd_info *i) {
360 assert(i);
361
362 pthread_mutex_lock(&i->mutex);
363 assert(i->ref >= 1);
364 i->ref++;
365
366 debug(DEBUG_LEVEL_VERBOSE, __FILE__": ref++, now %i\n", i->ref);
367 pthread_mutex_unlock(&i->mutex);
368
369 return i;
370 }
371
372 static void fd_info_unref(fd_info *i) {
373 int r;
374 pthread_mutex_lock(&i->mutex);
375 assert(i->ref >= 1);
376 r = --i->ref;
377 debug(DEBUG_LEVEL_VERBOSE, __FILE__": ref--, now %i\n", i->ref);
378 pthread_mutex_unlock(&i->mutex);
379
380 if (r <= 0)
381 fd_info_free(i);
382 }
383
384 static void context_state_cb(pa_context *c, void *userdata) {
385 fd_info *i = userdata;
386 assert(c);
387
388 switch (pa_context_get_state(c)) {
389 case PA_CONTEXT_READY:
390 case PA_CONTEXT_TERMINATED:
391 case PA_CONTEXT_FAILED:
392 pa_threaded_mainloop_signal(i->mainloop, 0);
393 break;
394
395 case PA_CONTEXT_UNCONNECTED:
396 case PA_CONTEXT_CONNECTING:
397 case PA_CONTEXT_AUTHORIZING:
398 case PA_CONTEXT_SETTING_NAME:
399 break;
400 }
401 }
402
403 static void reset_params(fd_info *i) {
404 assert(i);
405
406 i->sample_spec.format = PA_SAMPLE_U8;
407 i->sample_spec.channels = 1;
408 i->sample_spec.rate = 8000;
409 i->fragment_size = 0;
410 i->n_fragments = 0;
411 }
412
413 static const char *client_name(char *buf, size_t n) {
414 char p[PATH_MAX];
415 const char *e;
416
417 if ((e = getenv("PADSP_CLIENT_NAME")))
418 return e;
419
420 if (pa_get_binary_name(p, sizeof(p)))
421 snprintf(buf, n, "OSS Emulation[%s]", p);
422 else
423 snprintf(buf, n, "OSS");
424
425 return buf;
426 }
427
428 static const char *stream_name(void) {
429 const char *e;
430
431 if ((e = getenv("PADSP_STREAM_NAME")))
432 return e;
433
434 return "Audio Stream";
435 }
436
437 static void atfork_prepare(void) {
438 fd_info *i;
439
440 debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_prepare() enter\n");
441
442 function_enter();
443
444 pthread_mutex_lock(&fd_infos_mutex);
445
446 for (i = fd_infos; i; i = i->next) {
447 pthread_mutex_lock(&i->mutex);
448 pa_threaded_mainloop_lock(i->mainloop);
449 }
450
451 pthread_mutex_lock(&func_mutex);
452
453
454 debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_prepare() exit\n");
455 }
456
457 static void atfork_parent(void) {
458 fd_info *i;
459
460 debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_parent() enter\n");
461
462 pthread_mutex_unlock(&func_mutex);
463
464 for (i = fd_infos; i; i = i->next) {
465 pa_threaded_mainloop_unlock(i->mainloop);
466 pthread_mutex_unlock(&i->mutex);
467 }
468
469 pthread_mutex_unlock(&fd_infos_mutex);
470
471 function_exit();
472
473 debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_parent() exit\n");
474 }
475
476 static void atfork_child(void) {
477 fd_info *i;
478
479 debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_child() enter\n");
480
481 /* We do only the bare minimum to get all fds closed */
482 pthread_mutex_init(&func_mutex, NULL);
483 pthread_mutex_init(&fd_infos_mutex, NULL);
484
485 for (i = fd_infos; i; i = i->next) {
486 pthread_mutex_init(&i->mutex, NULL);
487
488 if (i->context) {
489 pa_context_disconnect(i->context);
490 pa_context_unref(i->context);
491 i->context = NULL;
492 }
493
494 if (i->play_stream) {
495 pa_stream_unref(i->play_stream);
496 i->play_stream = NULL;
497 }
498
499 if (i->rec_stream) {
500 pa_stream_unref(i->rec_stream);
501 i->rec_stream = NULL;
502 }
503
504 if (i->app_fd >= 0) {
505 close(i->app_fd);
506 i->app_fd = -1;
507 }
508
509 if (i->thread_fd >= 0) {
510 close(i->thread_fd);
511 i->thread_fd = -1;
512 }
513
514 i->unusable = 1;
515 }
516
517 function_exit();
518
519 debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_child() exit\n");
520 }
521
522 static void install_atfork(void) {
523 pthread_atfork(atfork_prepare, atfork_parent, atfork_child);
524 }
525
526 static void stream_success_cb(pa_stream *s, int success, void *userdata) {
527 fd_info *i = userdata;
528
529 assert(s);
530 assert(i);
531
532 i->operation_success = success;
533 pa_threaded_mainloop_signal(i->mainloop, 0);
534 }
535
536 static void context_success_cb(pa_context *c, int success, void *userdata) {
537 fd_info *i = userdata;
538
539 assert(c);
540 assert(i);
541
542 i->operation_success = success;
543 pa_threaded_mainloop_signal(i->mainloop, 0);
544 }
545
546 static fd_info* fd_info_new(fd_info_type_t type, int *_errno) {
547 fd_info *i;
548 int sfds[2] = { -1, -1 };
549 char name[64];
550 static pthread_once_t install_atfork_once = PTHREAD_ONCE_INIT;
551
552 debug(DEBUG_LEVEL_NORMAL, __FILE__": fd_info_new()\n");
553
554 signal(SIGPIPE, SIG_IGN); /* Yes, ugly as hell */
555
556 pthread_once(&install_atfork_once, install_atfork);
557
558 if (!(i = malloc(sizeof(fd_info)))) {
559 *_errno = ENOMEM;
560 goto fail;
561 }
562
563 i->app_fd = i->thread_fd = -1;
564 i->type = type;
565
566 i->mainloop = NULL;
567 i->context = NULL;
568 i->play_stream = NULL;
569 i->rec_stream = NULL;
570 i->io_event = NULL;
571 i->io_flags = 0;
572 pthread_mutex_init(&i->mutex, NULL);
573 i->ref = 1;
574 i->buf = NULL;
575 i->rec_offset = 0;
576 i->unusable = 0;
577 pa_cvolume_reset(&i->sink_volume, 2);
578 pa_cvolume_reset(&i->source_volume, 2);
579 i->volume_modify_count = 0;
580 i->sink_index = (uint32_t) -1;
581 i->source_index = (uint32_t) -1;
582 PA_LLIST_INIT(fd_info, i);
583
584 reset_params(i);
585
586 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfds) < 0) {
587 *_errno = errno;
588 debug(DEBUG_LEVEL_NORMAL, __FILE__": socket() failed: %s\n", strerror(errno));
589 goto fail;
590 }
591
592 i->app_fd = sfds[0];
593 i->thread_fd = sfds[1];
594
595 if (!(i->mainloop = pa_threaded_mainloop_new())) {
596 *_errno = EIO;
597 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_threaded_mainloop_new() failed\n");
598 goto fail;
599 }
600
601 if (!(i->context = pa_context_new(pa_threaded_mainloop_get_api(i->mainloop), client_name(name, sizeof(name))))) {
602 *_errno = EIO;
603 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_context_new() failed\n");
604 goto fail;
605 }
606
607 pa_context_set_state_callback(i->context, context_state_cb, i);
608
609 if (pa_context_connect(i->context, NULL, 0, NULL) < 0) {
610 *_errno = ECONNREFUSED;
611 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
612 goto fail;
613 }
614
615 pa_threaded_mainloop_lock(i->mainloop);
616
617 if (pa_threaded_mainloop_start(i->mainloop) < 0) {
618 *_errno = EIO;
619 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_threaded_mainloop_start() failed\n");
620 goto unlock_and_fail;
621 }
622
623 /* Wait until the context is ready */
624 pa_threaded_mainloop_wait(i->mainloop);
625
626 if (pa_context_get_state(i->context) != PA_CONTEXT_READY) {
627 *_errno = ECONNREFUSED;
628 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
629 goto unlock_and_fail;
630 }
631
632 pa_threaded_mainloop_unlock(i->mainloop);
633 return i;
634
635 unlock_and_fail:
636
637 pa_threaded_mainloop_unlock(i->mainloop);
638
639 fail:
640
641 if (i)
642 fd_info_unref(i);
643
644 return NULL;
645 }
646
647 static void fd_info_add_to_list(fd_info *i) {
648 assert(i);
649
650 pthread_mutex_lock(&fd_infos_mutex);
651 PA_LLIST_PREPEND(fd_info, fd_infos, i);
652 pthread_mutex_unlock(&fd_infos_mutex);
653
654 fd_info_ref(i);
655 }
656
657 static void fd_info_remove_from_list(fd_info *i) {
658 assert(i);
659
660 pthread_mutex_lock(&fd_infos_mutex);
661 PA_LLIST_REMOVE(fd_info, fd_infos, i);
662 pthread_mutex_unlock(&fd_infos_mutex);
663
664 fd_info_unref(i);
665 }
666
667 static fd_info* fd_info_find(int fd) {
668 fd_info *i;
669
670 pthread_mutex_lock(&fd_infos_mutex);
671
672 for (i = fd_infos; i; i = i->next)
673 if (i->app_fd == fd && !i->unusable) {
674 fd_info_ref(i);
675 break;
676 }
677
678 pthread_mutex_unlock(&fd_infos_mutex);
679
680 return i;
681 }
682
683 static void fix_metrics(fd_info *i) {
684 size_t fs;
685 char t[PA_SAMPLE_SPEC_SNPRINT_MAX];
686
687 fs = pa_frame_size(&i->sample_spec);
688
689 /* Don't fix things more than necessary */
690 if ((i->fragment_size % fs) == 0 &&
691 i->n_fragments >= 2 &&
692 i->fragment_size > 0)
693 return;
694
695 i->fragment_size = (i->fragment_size/fs)*fs;
696
697 /* Number of fragments set? */
698 if (i->n_fragments < 2) {
699 if (i->fragment_size > 0) {
700 i->n_fragments = pa_bytes_per_second(&i->sample_spec) / 2 / i->fragment_size;
701 if (i->n_fragments < 2)
702 i->n_fragments = 2;
703 } else
704 i->n_fragments = 12;
705 }
706
707 /* Fragment size set? */
708 if (i->fragment_size <= 0) {
709 i->fragment_size = pa_bytes_per_second(&i->sample_spec) / 2 / i->n_fragments;
710 if (i->fragment_size < 1024)
711 i->fragment_size = 1024;
712 }
713
714 debug(DEBUG_LEVEL_NORMAL, __FILE__": sample spec: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec));
715 debug(DEBUG_LEVEL_NORMAL, __FILE__": fixated metrics to %i fragments, %li bytes each.\n", i->n_fragments, (long)i->fragment_size);
716 }
717
718 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
719 fd_info *i = userdata;
720 assert(s);
721
722 if (i->io_event) {
723 pa_mainloop_api *api;
724 size_t n;
725
726 api = pa_threaded_mainloop_get_api(i->mainloop);
727
728 if (s == i->play_stream) {
729 n = pa_stream_writable_size(i->play_stream);
730 if (n == (size_t)-1) {
731 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n",
732 pa_strerror(pa_context_errno(i->context)));
733 }
734
735 if (n >= i->fragment_size)
736 i->io_flags |= PA_IO_EVENT_INPUT;
737 else
738 i->io_flags &= ~PA_IO_EVENT_INPUT;
739 }
740
741 if (s == i->rec_stream) {
742 n = pa_stream_readable_size(i->rec_stream);
743 if (n == (size_t)-1) {
744 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_readable_size(): %s\n",
745 pa_strerror(pa_context_errno(i->context)));
746 }
747
748 if (n >= i->fragment_size)
749 i->io_flags |= PA_IO_EVENT_OUTPUT;
750 else
751 i->io_flags &= ~PA_IO_EVENT_OUTPUT;
752 }
753
754 api->io_enable(i->io_event, i->io_flags);
755 }
756 }
757
758 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
759 fd_info *i = userdata;
760 assert(s);
761
762 pa_threaded_mainloop_signal(i->mainloop, 0);
763 }
764
765 static void fd_info_shutdown(fd_info *i) {
766 assert(i);
767
768 if (i->io_event) {
769 pa_mainloop_api *api;
770 api = pa_threaded_mainloop_get_api(i->mainloop);
771 api->io_free(i->io_event);
772 i->io_event = NULL;
773 i->io_flags = 0;
774 }
775
776 if (i->thread_fd >= 0) {
777 close(i->thread_fd);
778 i->thread_fd = -1;
779 }
780 }
781
782 static int fd_info_copy_data(fd_info *i, int force) {
783 size_t n;
784
785 if (!i->play_stream && !i->rec_stream)
786 return -1;
787
788 if ((i->play_stream) && (pa_stream_get_state(i->play_stream) == PA_STREAM_READY)) {
789 n = pa_stream_writable_size(i->play_stream);
790
791 if (n == (size_t)-1) {
792 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n",
793 pa_strerror(pa_context_errno(i->context)));
794 return -1;
795 }
796
797 while (n >= i->fragment_size || force) {
798 ssize_t r;
799
800 if (!i->buf) {
801 if (!(i->buf = malloc(i->fragment_size))) {
802 debug(DEBUG_LEVEL_NORMAL, __FILE__": malloc() failed.\n");
803 return -1;
804 }
805 }
806
807 if ((r = read(i->thread_fd, i->buf, i->fragment_size)) <= 0) {
808
809 if (errno == EAGAIN)
810 break;
811
812 debug(DEBUG_LEVEL_NORMAL, __FILE__": read(): %s\n", r == 0 ? "EOF" : strerror(errno));
813 return -1;
814 }
815
816 if (pa_stream_write(i->play_stream, i->buf, r, free, 0, PA_SEEK_RELATIVE) < 0) {
817 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i->context)));
818 return -1;
819 }
820
821 i->buf = NULL;
822
823 assert(n >= (size_t) r);
824 n -= r;
825 }
826
827 if (n >= i->fragment_size)
828 i->io_flags |= PA_IO_EVENT_INPUT;
829 else
830 i->io_flags &= ~PA_IO_EVENT_INPUT;
831 }
832
833 if ((i->rec_stream) && (pa_stream_get_state(i->rec_stream) == PA_STREAM_READY)) {
834 n = pa_stream_readable_size(i->rec_stream);
835
836 if (n == (size_t)-1) {
837 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_readable_size(): %s\n",
838 pa_strerror(pa_context_errno(i->context)));
839 return -1;
840 }
841
842 while (n >= i->fragment_size || force) {
843 ssize_t r;
844 const void *data;
845 const char *buf;
846 size_t len;
847
848 if (pa_stream_peek(i->rec_stream, &data, &len) < 0) {
849 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_peek(): %s\n", pa_strerror(pa_context_errno(i->context)));
850 return -1;
851 }
852
853 if (!data)
854 break;
855
856 buf = (const char*)data + i->rec_offset;
857
858 if ((r = write(i->thread_fd, buf, len - i->rec_offset)) <= 0) {
859
860 if (errno == EAGAIN)
861 break;
862
863 debug(DEBUG_LEVEL_NORMAL, __FILE__": write(): %s\n", strerror(errno));
864 return -1;
865 }
866
867 assert((size_t)r <= len - i->rec_offset);
868 i->rec_offset += r;
869
870 if (i->rec_offset == len) {
871 if (pa_stream_drop(i->rec_stream) < 0) {
872 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drop(): %s\n", pa_strerror(pa_context_errno(i->context)));
873 return -1;
874 }
875 i->rec_offset = 0;
876 }
877
878 assert(n >= (size_t) r);
879 n -= r;
880 }
881
882 if (n >= i->fragment_size)
883 i->io_flags |= PA_IO_EVENT_OUTPUT;
884 else
885 i->io_flags &= ~PA_IO_EVENT_OUTPUT;
886 }
887
888 if (i->io_event) {
889 pa_mainloop_api *api;
890
891 api = pa_threaded_mainloop_get_api(i->mainloop);
892 api->io_enable(i->io_event, i->io_flags);
893 }
894
895 return 0;
896 }
897
898 static void stream_state_cb(pa_stream *s, void * userdata) {
899 fd_info *i = userdata;
900 assert(s);
901
902 switch (pa_stream_get_state(s)) {
903
904 case PA_STREAM_READY:
905 debug(DEBUG_LEVEL_NORMAL, __FILE__": stream established.\n");
906 break;
907
908 case PA_STREAM_FAILED:
909 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
910 fd_info_shutdown(i);
911 break;
912
913 case PA_STREAM_TERMINATED:
914 case PA_STREAM_UNCONNECTED:
915 case PA_STREAM_CREATING:
916 break;
917 }
918 }
919
920 static int create_playback_stream(fd_info *i) {
921 pa_buffer_attr attr;
922 int n;
923
924 assert(i);
925
926 fix_metrics(i);
927
928 if (!(i->play_stream = pa_stream_new(i->context, stream_name(), &i->sample_spec, NULL))) {
929 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
930 goto fail;
931 }
932
933 pa_stream_set_state_callback(i->play_stream, stream_state_cb, i);
934 pa_stream_set_write_callback(i->play_stream, stream_request_cb, i);
935 pa_stream_set_latency_update_callback(i->play_stream, stream_latency_update_cb, i);
936
937 memset(&attr, 0, sizeof(attr));
938 attr.maxlength = i->fragment_size * (i->n_fragments+1);
939 attr.tlength = i->fragment_size * i->n_fragments;
940 attr.prebuf = i->fragment_size;
941 attr.minreq = i->fragment_size;
942
943 if (pa_stream_connect_playback(i->play_stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) {
944 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
945 goto fail;
946 }
947
948 n = i->fragment_size;
949 setsockopt(i->app_fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n));
950 n = i->fragment_size;
951 setsockopt(i->thread_fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));
952
953 return 0;
954
955 fail:
956 return -1;
957 }
958
959 static int create_record_stream(fd_info *i) {
960 pa_buffer_attr attr;
961 int n;
962
963 assert(i);
964
965 fix_metrics(i);
966
967 if (!(i->rec_stream = pa_stream_new(i->context, stream_name(), &i->sample_spec, NULL))) {
968 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
969 goto fail;
970 }
971
972 pa_stream_set_state_callback(i->rec_stream, stream_state_cb, i);
973 pa_stream_set_read_callback(i->rec_stream, stream_request_cb, i);
974 pa_stream_set_latency_update_callback(i->rec_stream, stream_latency_update_cb, i);
975
976 memset(&attr, 0, sizeof(attr));
977 attr.maxlength = i->fragment_size * (i->n_fragments+1);
978 attr.fragsize = i->fragment_size;
979
980 if (pa_stream_connect_record(i->rec_stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE) < 0) {
981 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
982 goto fail;
983 }
984
985 n = i->fragment_size;
986 setsockopt(i->app_fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));
987 n = i->fragment_size;
988 setsockopt(i->thread_fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n));
989
990 return 0;
991
992 fail:
993 return -1;
994 }
995
996 static void free_streams(fd_info *i) {
997 assert(i);
998
999 if (i->play_stream) {
1000 pa_stream_disconnect(i->play_stream);
1001 pa_stream_unref(i->play_stream);
1002 i->play_stream = NULL;
1003 }
1004
1005 if (i->rec_stream) {
1006 pa_stream_disconnect(i->rec_stream);
1007 pa_stream_unref(i->rec_stream);
1008 i->rec_stream = NULL;
1009 }
1010 }
1011
1012 static void io_event_cb(pa_mainloop_api *api, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) {
1013 fd_info *i = userdata;
1014
1015 pa_threaded_mainloop_signal(i->mainloop, 0);
1016
1017 if (flags & PA_IO_EVENT_INPUT) {
1018
1019 if (!i->play_stream) {
1020 if (create_playback_stream(i) < 0)
1021 goto fail;
1022 } else {
1023 if (fd_info_copy_data(i, 0) < 0)
1024 goto fail;
1025 }
1026
1027 } else if (flags & PA_IO_EVENT_OUTPUT) {
1028
1029 if (!i->rec_stream) {
1030 if (create_record_stream(i) < 0)
1031 goto fail;
1032 } else {
1033 if (fd_info_copy_data(i, 0) < 0)
1034 goto fail;
1035 }
1036
1037 } else if (flags & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR))
1038 goto fail;
1039
1040 return;
1041
1042 fail:
1043 /* We can't do anything better than removing the event source */
1044 fd_info_shutdown(i);
1045 }
1046
1047 static int dsp_open(int flags, int *_errno) {
1048 fd_info *i;
1049 pa_mainloop_api *api;
1050 int ret;
1051 int f;
1052
1053 debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open()\n");
1054
1055 if (!(i = fd_info_new(FD_INFO_STREAM, _errno)))
1056 return -1;
1057
1058 if ((flags & O_NONBLOCK) == O_NONBLOCK) {
1059 if ((f = fcntl(i->app_fd, F_GETFL)) >= 0)
1060 fcntl(i->app_fd, F_SETFL, f|O_NONBLOCK);
1061 }
1062 if ((f = fcntl(i->thread_fd, F_GETFL)) >= 0)
1063 fcntl(i->thread_fd, F_SETFL, f|O_NONBLOCK);
1064
1065 fcntl(i->app_fd, F_SETFD, FD_CLOEXEC);
1066 fcntl(i->thread_fd, F_SETFD, FD_CLOEXEC);
1067
1068 pa_threaded_mainloop_lock(i->mainloop);
1069 api = pa_threaded_mainloop_get_api(i->mainloop);
1070
1071 switch (flags & O_ACCMODE) {
1072 case O_RDONLY:
1073 i->io_flags = PA_IO_EVENT_OUTPUT;
1074 shutdown(i->thread_fd, SHUT_RD);
1075 shutdown(i->app_fd, SHUT_WR);
1076 break;
1077 case O_WRONLY:
1078 i->io_flags = PA_IO_EVENT_INPUT;
1079 shutdown(i->thread_fd, SHUT_WR);
1080 shutdown(i->app_fd, SHUT_RD);
1081 break;
1082 case O_RDWR:
1083 i->io_flags = PA_IO_EVENT_INPUT | PA_IO_EVENT_OUTPUT;
1084 break;
1085 default:
1086 return -1;
1087 }
1088
1089 if (!(i->io_event = api->io_new(api, i->thread_fd, i->io_flags, io_event_cb, i)))
1090 goto fail;
1091
1092 pa_threaded_mainloop_unlock(i->mainloop);
1093
1094 debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open() succeeded, fd=%i\n", i->app_fd);
1095
1096 fd_info_add_to_list(i);
1097 ret = i->app_fd;
1098 fd_info_unref(i);
1099
1100 return ret;
1101
1102 fail:
1103 pa_threaded_mainloop_unlock(i->mainloop);
1104
1105 if (i)
1106 fd_info_unref(i);
1107
1108 *_errno = EIO;
1109
1110 debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open() failed\n");
1111
1112 return -1;
1113 }
1114
1115 static void sink_info_cb(pa_context *context, const pa_sink_info *si, int eol, void *userdata) {
1116 fd_info *i = userdata;
1117
1118 if (!si && eol < 0) {
1119 i->operation_success = 0;
1120 pa_threaded_mainloop_signal(i->mainloop, 0);
1121 return;
1122 }
1123
1124 if (eol)
1125 return;
1126
1127 if (!pa_cvolume_equal(&i->sink_volume, &si->volume))
1128 i->volume_modify_count++;
1129
1130 i->sink_volume = si->volume;
1131 i->sink_index = si->index;
1132
1133 i->operation_success = 1;
1134 pa_threaded_mainloop_signal(i->mainloop, 0);
1135 }
1136
1137 static void source_info_cb(pa_context *context, const pa_source_info *si, int eol, void *userdata) {
1138 fd_info *i = userdata;
1139
1140 if (!si && eol < 0) {
1141 i->operation_success = 0;
1142 pa_threaded_mainloop_signal(i->mainloop, 0);
1143 return;
1144 }
1145
1146 if (eol)
1147 return;
1148
1149 if (!pa_cvolume_equal(&i->source_volume, &si->volume))
1150 i->volume_modify_count++;
1151
1152 i->source_volume = si->volume;
1153 i->source_index = si->index;
1154
1155 i->operation_success = 1;
1156 pa_threaded_mainloop_signal(i->mainloop, 0);
1157 }
1158
1159 static void subscribe_cb(pa_context *context, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
1160 fd_info *i = userdata;
1161 pa_operation *o = NULL;
1162
1163 if (i->sink_index != idx)
1164 return;
1165
1166 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
1167 return;
1168
1169 if (!(o = pa_context_get_sink_info_by_index(i->context, i->sink_index, sink_info_cb, i))) {
1170 debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context)));
1171 return;
1172 }
1173
1174 pa_operation_unref(o);
1175 }
1176
1177 static int mixer_open(int flags, int *_errno) {
1178 fd_info *i;
1179 pa_operation *o = NULL;
1180 int ret;
1181
1182 debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open()\n");
1183
1184 if (!(i = fd_info_new(FD_INFO_MIXER, _errno)))
1185 return -1;
1186
1187 pa_threaded_mainloop_lock(i->mainloop);
1188
1189 pa_context_set_subscribe_callback(i->context, subscribe_cb, i);
1190
1191 if (!(o = pa_context_subscribe(i->context, PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE, context_success_cb, i))) {
1192 debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context)));
1193 *_errno = EIO;
1194 goto fail;
1195 }
1196
1197 i->operation_success = 0;
1198 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1199 pa_threaded_mainloop_wait(i->mainloop);
1200 CONTEXT_CHECK_DEAD_GOTO(i, fail);
1201 }
1202
1203 pa_operation_unref(o);
1204 o = NULL;
1205
1206 if (!i->operation_success) {
1207 debug(DEBUG_LEVEL_NORMAL, __FILE__":Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context)));
1208 *_errno = EIO;
1209 goto fail;
1210 }
1211
1212 /* Get sink info */
1213
1214 if (!(o = pa_context_get_sink_info_by_name(i->context, NULL, sink_info_cb, i))) {
1215 debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context)));
1216 *_errno = EIO;
1217 goto fail;
1218 }
1219
1220 i->operation_success = 0;
1221 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1222 pa_threaded_mainloop_wait(i->mainloop);
1223 CONTEXT_CHECK_DEAD_GOTO(i, fail);
1224 }
1225
1226 pa_operation_unref(o);
1227 o = NULL;
1228
1229 if (!i->operation_success) {
1230 debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context)));
1231 *_errno = EIO;
1232 goto fail;
1233 }
1234
1235 /* Get source info */
1236
1237 if (!(o = pa_context_get_source_info_by_name(i->context, NULL, source_info_cb, i))) {
1238 debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get source info: %s", pa_strerror(pa_context_errno(i->context)));
1239 *_errno = EIO;
1240 goto fail;
1241 }
1242
1243 i->operation_success = 0;
1244 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1245 pa_threaded_mainloop_wait(i->mainloop);
1246 CONTEXT_CHECK_DEAD_GOTO(i, fail);
1247 }
1248
1249 pa_operation_unref(o);
1250 o = NULL;
1251
1252 if (!i->operation_success) {
1253 debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get source info: %s", pa_strerror(pa_context_errno(i->context)));
1254 *_errno = EIO;
1255 goto fail;
1256 }
1257
1258 pa_threaded_mainloop_unlock(i->mainloop);
1259
1260 debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open() succeeded, fd=%i\n", i->app_fd);
1261
1262 fd_info_add_to_list(i);
1263 ret = i->app_fd;
1264 fd_info_unref(i);
1265
1266 return ret;
1267
1268 fail:
1269 if (o)
1270 pa_operation_unref(o);
1271
1272 pa_threaded_mainloop_unlock(i->mainloop);
1273
1274 if (i)
1275 fd_info_unref(i);
1276
1277 *_errno = EIO;
1278
1279 debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open() failed\n");
1280
1281 return -1;
1282 }
1283
1284 static int sndstat_open(int flags, int *_errno) {
1285 static const char sndstat[] =
1286 "Sound Driver:3.8.1a-980706 (PulseAudio Virtual OSS)\n"
1287 "Kernel: POSIX\n"
1288 "Config options: 0\n"
1289 "\n"
1290 "Installed drivers:\n"
1291 "Type 255: PulseAudio Virtual OSS\n"
1292 "\n"
1293 "Card config:\n"
1294 "PulseAudio Virtual OSS\n"
1295 "\n"
1296 "Audio devices:\n"
1297 "0: PulseAudio Virtual OSS\n"
1298 "\n"
1299 "Synth devices: NOT ENABLED IN CONFIG\n"
1300 "\n"
1301 "Midi devices:\n"
1302 "\n"
1303 "Timers:\n"
1304 "\n"
1305 "Mixers:\n"
1306 "0: PulseAudio Virtual OSS\n";
1307
1308 char fn[] = "/tmp/padsp-sndstat-XXXXXX";
1309 mode_t u;
1310 int fd = -1;
1311 int e;
1312
1313 debug(DEBUG_LEVEL_NORMAL, __FILE__": sndstat_open()\n");
1314
1315 if (flags != O_RDONLY
1316 #ifdef O_LARGEFILE
1317 && flags != (O_RDONLY|O_LARGEFILE)
1318 #endif
1319 ) {
1320 *_errno = EACCES;
1321 debug(DEBUG_LEVEL_NORMAL, __FILE__": bad access!\n");
1322 goto fail;
1323 }
1324
1325 u = umask(0077);
1326 fd = mkstemp(fn);
1327 e = errno;
1328 umask(u);
1329
1330 if (fd < 0) {
1331 *_errno = e;
1332 debug(DEBUG_LEVEL_NORMAL, __FILE__": mkstemp() failed: %s\n", strerror(errno));
1333 goto fail;
1334 }
1335
1336 unlink(fn);
1337
1338 if (write(fd, sndstat, sizeof(sndstat) -1) != sizeof(sndstat)-1) {
1339 *_errno = errno;
1340 debug(DEBUG_LEVEL_NORMAL, __FILE__": write() failed: %s\n", strerror(errno));
1341 goto fail;
1342 }
1343
1344 if (lseek(fd, SEEK_SET, 0) < 0) {
1345 *_errno = errno;
1346 debug(DEBUG_LEVEL_NORMAL, __FILE__": lseek() failed: %s\n", strerror(errno));
1347 goto fail;
1348 }
1349
1350 return fd;
1351
1352 fail:
1353 if (fd >= 0)
1354 close(fd);
1355 return -1;
1356 }
1357
1358 int open(const char *filename, int flags, ...) {
1359 va_list args;
1360 mode_t mode = 0;
1361 int r, _errno = 0;
1362
1363 debug(DEBUG_LEVEL_VERBOSE, __FILE__": open(%s)\n", filename);
1364
1365 va_start(args, flags);
1366 if (flags & O_CREAT) {
1367 if (sizeof(mode_t) < sizeof(int))
1368 mode = va_arg(args, int);
1369 else
1370 mode = va_arg(args, mode_t);
1371 }
1372 va_end(args);
1373
1374 if (!function_enter()) {
1375 LOAD_OPEN_FUNC();
1376 return _open(filename, flags, mode);
1377 }
1378
1379 if (dsp_cloak_enable() && (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0)) {
1380 r = dsp_open(flags, &_errno);
1381 } else if (mixer_cloak_enable() && strcmp(filename, "/dev/mixer") == 0) {
1382 r = mixer_open(flags, &_errno);
1383 } else if (sndstat_cloak_enable() && strcmp(filename, "/dev/sndstat") == 0) {
1384 r = sndstat_open(flags, &_errno);
1385 } else {
1386 function_exit();
1387 LOAD_OPEN_FUNC();
1388 return _open(filename, flags, mode);
1389 }
1390
1391 function_exit();
1392
1393 if (_errno)
1394 errno = _errno;
1395
1396 return r;
1397 }
1398
1399 static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) {
1400 int ret = -1;
1401
1402 switch (request) {
1403 case SOUND_MIXER_READ_DEVMASK :
1404 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_DEVMASK\n");
1405
1406 *(int*) argp = SOUND_MASK_PCM | SOUND_MASK_IGAIN;
1407 break;
1408
1409 case SOUND_MIXER_READ_RECMASK :
1410 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_RECMASK\n");
1411
1412 *(int*) argp = SOUND_MASK_IGAIN;
1413 break;
1414
1415 case SOUND_MIXER_READ_STEREODEVS:
1416 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_STEREODEVS\n");
1417
1418 pa_threaded_mainloop_lock(i->mainloop);
1419 *(int*) argp = 0;
1420 if (i->sink_volume.channels > 1)
1421 *(int*) argp |= SOUND_MASK_PCM;
1422 if (i->source_volume.channels > 1)
1423 *(int*) argp |= SOUND_MASK_IGAIN;
1424 pa_threaded_mainloop_unlock(i->mainloop);
1425
1426 break;
1427
1428 case SOUND_MIXER_READ_RECSRC:
1429 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_RECSRC\n");
1430
1431 *(int*) argp = SOUND_MASK_IGAIN;
1432 break;
1433
1434 case SOUND_MIXER_WRITE_RECSRC:
1435 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_RECSRC\n");
1436 break;
1437
1438 case SOUND_MIXER_READ_CAPS:
1439 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_CAPS\n");
1440
1441 *(int*) argp = 0;
1442 break;
1443
1444 case SOUND_MIXER_READ_PCM:
1445 case SOUND_MIXER_READ_IGAIN: {
1446 pa_cvolume *v;
1447
1448 if (request == SOUND_MIXER_READ_PCM)
1449 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_PCM\n");
1450 else
1451 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_IGAIN\n");
1452
1453 pa_threaded_mainloop_lock(i->mainloop);
1454
1455 if (request == SOUND_MIXER_READ_PCM)
1456 v = &i->sink_volume;
1457 else
1458 v = &i->source_volume;
1459
1460 *(int*) argp =
1461 ((v->values[0]*100/PA_VOLUME_NORM)) |
1462 ((v->values[v->channels > 1 ? 1 : 0]*100/PA_VOLUME_NORM) << 8);
1463
1464 pa_threaded_mainloop_unlock(i->mainloop);
1465
1466 break;
1467 }
1468
1469 case SOUND_MIXER_WRITE_PCM:
1470 case SOUND_MIXER_WRITE_IGAIN: {
1471 pa_cvolume v, *pv;
1472
1473 if (request == SOUND_MIXER_READ_PCM)
1474 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_PCM\n");
1475 else
1476 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_IGAIN\n");
1477
1478 pa_threaded_mainloop_lock(i->mainloop);
1479
1480 if (request == SOUND_MIXER_READ_PCM) {
1481 v = i->sink_volume;
1482 pv = &i->sink_volume;
1483 } else {
1484 v = i->source_volume;
1485 pv = &i->source_volume;
1486 }
1487
1488 pv->values[0] = ((*(int*) argp & 0xFF)*PA_VOLUME_NORM)/100;
1489 pv->values[1] = ((*(int*) argp >> 8)*PA_VOLUME_NORM)/100;
1490
1491 if (!pa_cvolume_equal(pv, &v)) {
1492 pa_operation *o;
1493
1494 if (request == SOUND_MIXER_READ_PCM)
1495 o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, pv, context_success_cb, i);
1496 else
1497 o = pa_context_set_source_volume_by_index(i->context, i->source_index, pv, context_success_cb, i);
1498
1499 if (!o)
1500 debug(DEBUG_LEVEL_NORMAL, __FILE__":Failed set volume: %s", pa_strerror(pa_context_errno(i->context)));
1501 else {
1502
1503 i->operation_success = 0;
1504 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1505 CONTEXT_CHECK_DEAD_GOTO(i, exit_loop);
1506
1507 pa_threaded_mainloop_wait(i->mainloop);
1508 }
1509 exit_loop:
1510
1511 if (!i->operation_success)
1512 debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to set volume: %s\n", pa_strerror(pa_context_errno(i->context)));
1513
1514 pa_operation_unref(o);
1515 }
1516
1517 /* We don't wait for completion here */
1518 i->volume_modify_count++;
1519 }
1520
1521 pa_threaded_mainloop_unlock(i->mainloop);
1522
1523 break;
1524 }
1525
1526 case SOUND_MIXER_INFO: {
1527 mixer_info *mi = argp;
1528
1529 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_INFO\n");
1530
1531 memset(mi, 0, sizeof(mixer_info));
1532 strncpy(mi->id, "PULSEAUDIO", sizeof(mi->id));
1533 strncpy(mi->name, "PulseAudio Virtual OSS", sizeof(mi->name));
1534 pa_threaded_mainloop_lock(i->mainloop);
1535 mi->modify_counter = i->volume_modify_count;
1536 pa_threaded_mainloop_unlock(i->mainloop);
1537 break;
1538 }
1539
1540 default:
1541 debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request);
1542
1543 *_errno = EINVAL;
1544 goto fail;
1545 }
1546
1547 ret = 0;
1548
1549 fail:
1550
1551 return ret;
1552 }
1553
1554 static int map_format(int *fmt, pa_sample_spec *ss) {
1555
1556 switch (*fmt) {
1557 case AFMT_MU_LAW:
1558 ss->format = PA_SAMPLE_ULAW;
1559 break;
1560
1561 case AFMT_A_LAW:
1562 ss->format = PA_SAMPLE_ALAW;
1563 break;
1564
1565 case AFMT_S8:
1566 *fmt = AFMT_U8;
1567 /* fall through */
1568 case AFMT_U8:
1569 ss->format = PA_SAMPLE_U8;
1570 break;
1571
1572 case AFMT_U16_BE:
1573 *fmt = AFMT_S16_BE;
1574 /* fall through */
1575 case AFMT_S16_BE:
1576 ss->format = PA_SAMPLE_S16BE;
1577 break;
1578
1579 case AFMT_U16_LE:
1580 *fmt = AFMT_S16_LE;
1581 /* fall through */
1582 case AFMT_S16_LE:
1583 ss->format = PA_SAMPLE_S16LE;
1584 break;
1585
1586 default:
1587 ss->format = PA_SAMPLE_S16NE;
1588 *fmt = AFMT_S16_NE;
1589 break;
1590 }
1591
1592 return 0;
1593 }
1594
1595 static int map_format_back(pa_sample_format_t format) {
1596 switch (format) {
1597 case PA_SAMPLE_S16LE: return AFMT_S16_LE;
1598 case PA_SAMPLE_S16BE: return AFMT_S16_BE;
1599 case PA_SAMPLE_ULAW: return AFMT_MU_LAW;
1600 case PA_SAMPLE_ALAW: return AFMT_A_LAW;
1601 case PA_SAMPLE_U8: return AFMT_U8;
1602 default:
1603 abort();
1604 }
1605 }
1606
1607 static int dsp_flush_fd(int fd) {
1608 #ifdef SIOCINQ
1609 int l;
1610
1611 if (ioctl(fd, SIOCINQ, &l) < 0) {
1612 debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ: %s\n", strerror(errno));
1613 return -1;
1614 }
1615
1616 while (l > 0) {
1617 char buf[1024];
1618 size_t k;
1619
1620 k = (size_t) l > sizeof(buf) ? sizeof(buf) : (size_t) l;
1621 if (read(fd, buf, k) < 0)
1622 debug(DEBUG_LEVEL_NORMAL, __FILE__": read(): %s\n", strerror(errno));
1623 l -= k;
1624 }
1625
1626 return 0;
1627 #else
1628 # warning "Your platform does not support SIOCINQ, something might not work as intended."
1629 return 0;
1630 #endif
1631 }
1632
1633 static int dsp_flush_socket(fd_info *i) {
1634 int res = 0;
1635
1636 if ((i->thread_fd < 0) && (i->app_fd < 0))
1637 return -1;
1638
1639 if (i->thread_fd >= 0)
1640 res = dsp_flush_fd(i->thread_fd);
1641
1642 if (res < 0)
1643 return res;
1644
1645 if (i->app_fd >= 0)
1646 res = dsp_flush_fd(i->app_fd);
1647
1648 if (res < 0)
1649 return res;
1650
1651 return 0;
1652 }
1653
1654 static int dsp_empty_socket(fd_info *i) {
1655 #ifdef SIOCINQ
1656 int ret = -1;
1657
1658 /* Empty the socket */
1659 for (;;) {
1660 int l;
1661
1662 if (i->thread_fd < 0)
1663 break;
1664
1665 if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) {
1666 debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ: %s\n", strerror(errno));
1667 break;
1668 }
1669
1670 if (!l) {
1671 ret = 0;
1672 break;
1673 }
1674
1675 pa_threaded_mainloop_wait(i->mainloop);
1676 }
1677
1678 return ret;
1679 #else
1680 # warning "Your platform does not support SIOCINQ, something might not work as intended."
1681 return 0;
1682 #endif
1683 }
1684
1685 static int dsp_drain(fd_info *i) {
1686 pa_operation *o = NULL;
1687 int r = -1;
1688
1689 if (!i->mainloop)
1690 return 0;
1691
1692 debug(DEBUG_LEVEL_NORMAL, __FILE__": Draining.\n");
1693
1694 pa_threaded_mainloop_lock(i->mainloop);
1695
1696 if (dsp_empty_socket(i) < 0)
1697 goto fail;
1698
1699 if (!i->play_stream)
1700 goto fail;
1701
1702 debug(DEBUG_LEVEL_NORMAL, __FILE__": Really draining.\n");
1703
1704 if (!(o = pa_stream_drain(i->play_stream, stream_success_cb, i))) {
1705 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context)));
1706 goto fail;
1707 }
1708
1709 i->operation_success = 0;
1710 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1711 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail);
1712
1713 pa_threaded_mainloop_wait(i->mainloop);
1714 }
1715
1716 if (!i->operation_success) {
1717 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i->context)));
1718 goto fail;
1719 }
1720
1721 r = 0;
1722
1723 fail:
1724
1725 if (o)
1726 pa_operation_unref(o);
1727
1728 pa_threaded_mainloop_unlock(i->mainloop);
1729
1730 return 0;
1731 }
1732
1733 static int dsp_trigger(fd_info *i) {
1734 pa_operation *o = NULL;
1735 int r = -1;
1736
1737 if (!i->play_stream)
1738 return 0;
1739
1740 pa_threaded_mainloop_lock(i->mainloop);
1741
1742 if (dsp_empty_socket(i) < 0)
1743 goto fail;
1744
1745 debug(DEBUG_LEVEL_NORMAL, __FILE__": Triggering.\n");
1746
1747 if (!(o = pa_stream_trigger(i->play_stream, stream_success_cb, i))) {
1748 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context)));
1749 goto fail;
1750 }
1751
1752 i->operation_success = 0;
1753 while (!pa_operation_get_state(o) != PA_OPERATION_DONE) {
1754 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail);
1755
1756 pa_threaded_mainloop_wait(i->mainloop);
1757 }
1758
1759 if (!i->operation_success) {
1760 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context)));
1761 goto fail;
1762 }
1763
1764 r = 0;
1765
1766 fail:
1767
1768 if (o)
1769 pa_operation_unref(o);
1770
1771 pa_threaded_mainloop_unlock(i->mainloop);
1772
1773 return 0;
1774 }
1775
1776 static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) {
1777 int ret = -1;
1778
1779 switch (request) {
1780 case SNDCTL_DSP_SETFMT: {
1781 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp);
1782
1783 pa_threaded_mainloop_lock(i->mainloop);
1784
1785 if (*(int*) argp == AFMT_QUERY)
1786 *(int*) argp = map_format_back(i->sample_spec.format);
1787 else {
1788 map_format((int*) argp, &i->sample_spec);
1789 free_streams(i);
1790 }
1791
1792 pa_threaded_mainloop_unlock(i->mainloop);
1793 break;
1794 }
1795
1796 case SNDCTL_DSP_SPEED: {
1797 pa_sample_spec ss;
1798 int valid;
1799 char t[256];
1800
1801 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SPEED: %i\n", *(int*) argp);
1802
1803 pa_threaded_mainloop_lock(i->mainloop);
1804
1805 ss = i->sample_spec;
1806 ss.rate = *(int*) argp;
1807
1808 if ((valid = pa_sample_spec_valid(&ss))) {
1809 i->sample_spec = ss;
1810 free_streams(i);
1811 }
1812
1813 debug(DEBUG_LEVEL_NORMAL, __FILE__": ss: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec));
1814
1815 pa_threaded_mainloop_unlock(i->mainloop);
1816
1817 if (!valid) {
1818 *_errno = EINVAL;
1819 goto fail;
1820 }
1821
1822 break;
1823 }
1824
1825 case SNDCTL_DSP_STEREO:
1826 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_STEREO: %i\n", *(int*) argp);
1827
1828 pa_threaded_mainloop_lock(i->mainloop);
1829
1830 i->sample_spec.channels = *(int*) argp ? 2 : 1;
1831 free_streams(i);
1832
1833 pa_threaded_mainloop_unlock(i->mainloop);
1834 return 0;
1835
1836 case SNDCTL_DSP_CHANNELS: {
1837 pa_sample_spec ss;
1838 int valid;
1839
1840 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp);
1841
1842 pa_threaded_mainloop_lock(i->mainloop);
1843
1844 ss = i->sample_spec;
1845 ss.channels = *(int*) argp;
1846
1847 if ((valid = pa_sample_spec_valid(&ss))) {
1848 i->sample_spec = ss;
1849 free_streams(i);
1850 }
1851
1852 pa_threaded_mainloop_unlock(i->mainloop);
1853
1854 if (!valid) {
1855 *_errno = EINVAL;
1856 goto fail;
1857 }
1858
1859 break;
1860 }
1861
1862 case SNDCTL_DSP_GETBLKSIZE:
1863 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETBLKSIZE\n");
1864
1865 pa_threaded_mainloop_lock(i->mainloop);
1866
1867 fix_metrics(i);
1868 *(int*) argp = i->fragment_size;
1869
1870 pa_threaded_mainloop_unlock(i->mainloop);
1871
1872 break;
1873
1874 case SNDCTL_DSP_SETFRAGMENT:
1875 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%8x\n", *(int*) argp);
1876
1877 pa_threaded_mainloop_lock(i->mainloop);
1878
1879 i->fragment_size = 1 << (*(int*) argp);
1880 i->n_fragments = (*(int*) argp) >> 16;
1881
1882 /* 0x7FFF means that we can set whatever we like */
1883 if (i->n_fragments == 0x7FFF)
1884 i->n_fragments = 12;
1885
1886 free_streams(i);
1887
1888 pa_threaded_mainloop_unlock(i->mainloop);
1889
1890 break;
1891
1892 case SNDCTL_DSP_GETCAPS:
1893 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CAPS\n");
1894
1895 *(int*) argp = DSP_CAP_DUPLEX
1896 #ifdef DSP_CAP_MULTI
1897 | DSP_CAP_MULTI
1898 #endif
1899 ;
1900 break;
1901
1902 case SNDCTL_DSP_GETODELAY: {
1903 int l;
1904
1905 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETODELAY\n");
1906
1907 pa_threaded_mainloop_lock(i->mainloop);
1908
1909 *(int*) argp = 0;
1910
1911 for (;;) {
1912 pa_usec_t usec;
1913
1914 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, exit_loop);
1915
1916 if (pa_stream_get_latency(i->play_stream, &usec, NULL) >= 0) {
1917 *(int*) argp = pa_usec_to_bytes(usec, &i->sample_spec);
1918 break;
1919 }
1920
1921 if (pa_context_errno(i->context) != PA_ERR_NODATA) {
1922 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i->context)));
1923 break;
1924 }
1925
1926 pa_threaded_mainloop_wait(i->mainloop);
1927 }
1928
1929 exit_loop:
1930
1931 #ifdef SIOCINQ
1932 if (ioctl(i->thread_fd, SIOCINQ, &l) < 0)
1933 debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno));
1934 else
1935 *(int*) argp += l;
1936 #else
1937 # warning "Your platform does not support SIOCINQ, something might not work as intended."
1938 #endif
1939
1940 pa_threaded_mainloop_unlock(i->mainloop);
1941
1942 debug(DEBUG_LEVEL_NORMAL, __FILE__": ODELAY: %i\n", *(int*) argp);
1943
1944 break;
1945 }
1946
1947 case SNDCTL_DSP_RESET: {
1948 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_RESET\n");
1949
1950 pa_threaded_mainloop_lock(i->mainloop);
1951
1952 free_streams(i);
1953 dsp_flush_socket(i);
1954 reset_params(i);
1955
1956 pa_threaded_mainloop_unlock(i->mainloop);
1957 break;
1958 }
1959
1960 case SNDCTL_DSP_GETFMTS: {
1961 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETFMTS\n");
1962
1963 *(int*) argp = AFMT_MU_LAW|AFMT_A_LAW|AFMT_U8|AFMT_S16_LE|AFMT_S16_BE;
1964 break;
1965 }
1966
1967 case SNDCTL_DSP_POST:
1968 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_POST\n");
1969
1970 if (dsp_trigger(i) < 0)
1971 *_errno = EIO;
1972 break;
1973
1974 case SNDCTL_DSP_SYNC:
1975 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SYNC\n");
1976
1977 if (dsp_drain(i) < 0)
1978 *_errno = EIO;
1979
1980 break;
1981
1982 case SNDCTL_DSP_GETOSPACE:
1983 case SNDCTL_DSP_GETISPACE: {
1984 audio_buf_info *bi = (audio_buf_info*) argp;
1985 int l = 0;
1986 size_t k = 0;
1987
1988 if (request == SNDCTL_DSP_GETOSPACE)
1989 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETOSPACE\n");
1990 else
1991 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETISPACE\n");
1992
1993 pa_threaded_mainloop_lock(i->mainloop);
1994
1995 fix_metrics(i);
1996
1997 if (request == SNDCTL_DSP_GETOSPACE) {
1998 if (i->play_stream) {
1999 if ((k = pa_stream_writable_size(i->play_stream)) == (size_t) -1)
2000 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context)));
2001 } else
2002 k = i->fragment_size * i->n_fragments;
2003
2004 #ifdef SIOCINQ
2005 if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) {
2006 debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno));
2007 l = 0;
2008 }
2009 #else
2010 # warning "Your platform does not dsp_flush_fd, something might not work as intended."
2011 #endif
2012
2013 bi->bytes = k > (size_t) l ? k - l : 0;
2014 } else {
2015 if (i->rec_stream) {
2016 if ((k = pa_stream_readable_size(i->rec_stream)) == (size_t) -1)
2017 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_readable_size(): %s\n", pa_strerror(pa_context_errno(i->context)));
2018 } else
2019 k = 0;
2020
2021 #ifdef SIOCINQ
2022 if (ioctl(i->app_fd, SIOCINQ, &l) < 0) {
2023 debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno));
2024 l = 0;
2025 }
2026 #else
2027 # warning "Your platform does not dsp_flush_fd, something might not work as intended."
2028 #endif
2029 bi->bytes = k + l;
2030 }
2031
2032 bi->fragsize = i->fragment_size;
2033 bi->fragstotal = i->n_fragments;
2034 bi->fragments = bi->bytes / bi->fragsize;
2035
2036 pa_threaded_mainloop_unlock(i->mainloop);
2037
2038 debug(DEBUG_LEVEL_NORMAL, __FILE__": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi->fragsize, bi->fragstotal, bi->bytes, bi->fragments);
2039
2040 break;
2041 }
2042
2043 case SNDCTL_DSP_GETIPTR:
2044 debug(DEBUG_LEVEL_NORMAL, __FILE__": invalid ioctl SNDCTL_DSP_GETIPTR\n");
2045 goto inval;
2046
2047 case SNDCTL_DSP_GETOPTR:
2048 debug(DEBUG_LEVEL_NORMAL, __FILE__": invalid ioctl SNDCTL_DSP_GETOPTR\n");
2049 goto inval;
2050
2051 default:
2052 debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request);
2053
2054 inval:
2055 *_errno = EINVAL;
2056 goto fail;
2057 }
2058
2059 ret = 0;
2060
2061 fail:
2062
2063 return ret;
2064 }
2065
2066 int ioctl(int fd, unsigned long request, ...) {
2067 fd_info *i;
2068 va_list args;
2069 void *argp;
2070 int r, _errno = 0;
2071
2072 debug(DEBUG_LEVEL_VERBOSE, __FILE__": ioctl()\n");
2073
2074 va_start(args, request);
2075 argp = va_arg(args, void *);
2076 va_end(args);
2077
2078 if (!function_enter()) {
2079 LOAD_IOCTL_FUNC();
2080 return _ioctl(fd, request, argp);
2081 }
2082
2083 if (!(i = fd_info_find(fd))) {
2084 function_exit();
2085 LOAD_IOCTL_FUNC();
2086 return _ioctl(fd, request, argp);
2087 }
2088
2089 if (i->type == FD_INFO_MIXER)
2090 r = mixer_ioctl(i, request, argp, &_errno);
2091 else
2092 r = dsp_ioctl(i, request, argp, &_errno);
2093
2094 fd_info_unref(i);
2095
2096 if (_errno)
2097 errno = _errno;
2098
2099 function_exit();
2100
2101 return r;
2102 }
2103
2104 int close(int fd) {
2105 fd_info *i;
2106
2107 debug(DEBUG_LEVEL_VERBOSE, __FILE__": close()\n");
2108
2109 if (!function_enter()) {
2110 LOAD_CLOSE_FUNC();
2111 return _close(fd);
2112 }
2113
2114 if (!(i = fd_info_find(fd))) {
2115 function_exit();
2116 LOAD_CLOSE_FUNC();
2117 return _close(fd);
2118 }
2119
2120 fd_info_remove_from_list(i);
2121 fd_info_unref(i);
2122
2123 function_exit();
2124
2125 return 0;
2126 }
2127
2128 int access(const char *pathname, int mode) {
2129
2130 if (!pathname) {
2131 /* Firefox needs this. See #27 */
2132 errno = EFAULT;
2133 return -1;
2134 }
2135
2136 debug(DEBUG_LEVEL_VERBOSE, __FILE__": access(%s)\n", pathname);
2137
2138 if (strcmp(pathname, "/dev/dsp") != 0 &&
2139 strcmp(pathname, "/dev/adsp") != 0 &&
2140 strcmp(pathname, "/dev/sndstat") != 0 &&
2141 strcmp(pathname, "/dev/mixer") != 0) {
2142 LOAD_ACCESS_FUNC();
2143 return _access(pathname, mode);
2144 }
2145
2146 if (mode & (W_OK | X_OK)) {
2147 debug(DEBUG_LEVEL_NORMAL, __FILE__": access(%s, %x) = EACCESS\n", pathname, mode);
2148 errno = EACCES;
2149 return -1;
2150 }
2151
2152 debug(DEBUG_LEVEL_NORMAL, __FILE__": access(%s, %x) = OK\n", pathname, mode);
2153
2154 return 0;
2155 }
2156
2157 #ifdef HAVE_OPEN64
2158
2159 int open64(const char *filename, int flags, ...) {
2160 va_list args;
2161 mode_t mode = 0;
2162
2163 debug(DEBUG_LEVEL_VERBOSE, __FILE__": open64(%s)\n", filename);
2164
2165 va_start(args, flags);
2166 if (flags & O_CREAT)
2167 mode = va_arg(args, mode_t);
2168 va_end(args);
2169
2170 if (strcmp(filename, "/dev/dsp") != 0 &&
2171 strcmp(filename, "/dev/adsp") != 0 &&
2172 strcmp(filename, "/dev/sndstat") != 0 &&
2173 strcmp(filename, "/dev/mixer") != 0) {
2174 LOAD_OPEN64_FUNC();
2175 return _open64(filename, flags, mode);
2176 }
2177
2178 return open(filename, flags, mode);
2179 }
2180
2181 #endif
2182
2183 FILE* fopen(const char *filename, const char *mode) {
2184 FILE *f = NULL;
2185 int fd;
2186 mode_t m;
2187
2188 debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen(%s)\n", filename);
2189
2190 if (strcmp(filename, "/dev/dsp") != 0 &&
2191 strcmp(filename, "/dev/adsp") != 0 &&
2192 strcmp(filename, "/dev/sndstat") != 0 &&
2193 strcmp(filename, "/dev/mixer") != 0) {
2194 LOAD_FOPEN_FUNC();
2195 return _fopen(filename, mode);
2196 }
2197
2198 switch (mode[0]) {
2199 case 'r':
2200 m = O_RDONLY;
2201 break;
2202 case 'w':
2203 case 'a':
2204 m = O_WRONLY;
2205 break;
2206 default:
2207 errno = EINVAL;
2208 return NULL;
2209 }
2210
2211 if ((((mode[1] == 'b') || (mode[1] == 't')) && (mode[2] == '+')) || (mode[1] == '+'))
2212 m = O_RDWR;
2213
2214 if ((fd = open(filename, m)) < 0)
2215 return NULL;
2216
2217 if (!(f = fdopen(fd, mode))) {
2218 close(fd);
2219 return NULL;
2220 }
2221
2222 return f;
2223 }
2224
2225 #ifdef HAVE_OPEN64
2226
2227 FILE *fopen64(const char *filename, const char *mode) {
2228
2229 debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen64(%s)\n", filename);
2230
2231 if (strcmp(filename, "/dev/dsp") != 0 &&
2232 strcmp(filename, "/dev/adsp") != 0 &&
2233 strcmp(filename, "/dev/sndstat") != 0 &&
2234 strcmp(filename, "/dev/mixer") != 0) {
2235 LOAD_FOPEN64_FUNC();
2236 return _fopen64(filename, mode);
2237 }
2238
2239 return fopen(filename, mode);
2240 }
2241
2242 #endif
2243
2244 int fclose(FILE *f) {
2245 fd_info *i;
2246
2247 debug(DEBUG_LEVEL_VERBOSE, __FILE__": fclose()\n");
2248
2249 if (!function_enter()) {
2250 LOAD_FCLOSE_FUNC();
2251 return _fclose(f);
2252 }
2253
2254 if (!(i = fd_info_find(fileno(f)))) {
2255 function_exit();
2256 LOAD_FCLOSE_FUNC();
2257 return _fclose(f);
2258 }
2259
2260 fd_info_remove_from_list(i);
2261
2262 /* Dirty trick to avoid that the fd is not freed twice, once by us
2263 * and once by the real fclose() */
2264 i->app_fd = -1;
2265
2266 fd_info_unref(i);
2267
2268 function_exit();
2269
2270 LOAD_FCLOSE_FUNC();
2271 return _fclose(f);
2272 }