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