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