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