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