]> code.delx.au - pulseaudio/blob - src/utils/padsp.c
Cast size_t to long to be more compatible with 64-bit systems.
[pulseaudio] / src / utils / padsp.c
1 /* $Id$ */
2
3 /***
4 This file is part of polypaudio.
5
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 polypaudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #ifdef _FILE_OFFSET_BITS
27 #undef _FILE_OFFSET_BITS
28 #endif
29
30 #ifndef _LARGEFILE64_SOURCE
31 #define _LARGEFILE64_SOURCE 1
32 #endif
33
34 #include <sys/soundcard.h>
35 #include <sys/ioctl.h>
36 #include <pthread.h>
37 #include <unistd.h>
38 #include <sys/socket.h>
39 #include <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 #include <linux/sockios.h>
48
49 #include <polyp/polypaudio.h>
50 #include <polypcore/llist.h>
51 #include <polypcore/gccmacro.h>
52
53 typedef enum {
54 FD_INFO_MIXER,
55 FD_INFO_PLAYBACK
56 } fd_info_type_t;
57
58 typedef struct fd_info fd_info;
59
60 struct fd_info {
61 pthread_mutex_t mutex;
62 int ref;
63
64 fd_info_type_t type;
65 int app_fd, thread_fd;
66
67 pa_sample_spec sample_spec;
68 size_t fragment_size;
69 unsigned n_fragments;
70
71 pa_threaded_mainloop *mainloop;
72 pa_context *context;
73 pa_stream *stream;
74
75 pa_io_event *io_event;
76
77 void *buf;
78
79 int operation_success;
80
81 PA_LLIST_FIELDS(fd_info);
82 };
83
84 static int dsp_drain(fd_info *i);
85
86 static pthread_mutex_t fd_infos_mutex = PTHREAD_MUTEX_INITIALIZER;
87 static pthread_mutex_t func_mutex = PTHREAD_MUTEX_INITIALIZER;
88
89 static PA_LLIST_HEAD(fd_info, fd_infos) = NULL;
90
91 static int (*_ioctl)(int, int, void*) = NULL;
92 static int (*_close)(int) = NULL;
93 static int (*_open)(const char *, int, mode_t) = NULL;
94 static FILE* (*_fopen)(const char *path, const char *mode) = NULL;
95 static int (*_open64)(const char *, int, mode_t) = NULL;
96 static FILE* (*_fopen64)(const char *path, const char *mode) = NULL;
97 static int (*_fclose)(FILE *f) = NULL;
98
99 #define LOAD_IOCTL_FUNC() \
100 do { \
101 pthread_mutex_lock(&func_mutex); \
102 if (!_ioctl) \
103 _ioctl = (int (*)(int, int, void*)) dlsym(RTLD_NEXT, "ioctl"); \
104 pthread_mutex_unlock(&func_mutex); \
105 } while(0)
106
107 #define LOAD_OPEN_FUNC() \
108 do { \
109 pthread_mutex_lock(&func_mutex); \
110 if (!_open) \
111 _open = (int (*)(const char *, int, mode_t)) dlsym(RTLD_NEXT, "open"); \
112 pthread_mutex_unlock(&func_mutex); \
113 } while(0)
114
115 #define LOAD_OPEN64_FUNC() \
116 do { \
117 pthread_mutex_lock(&func_mutex); \
118 if (!_open64) \
119 _open64 = (int (*)(const char *, int, mode_t)) dlsym(RTLD_NEXT, "open64"); \
120 pthread_mutex_unlock(&func_mutex); \
121 } while(0)
122
123 #define LOAD_CLOSE_FUNC() \
124 do { \
125 pthread_mutex_lock(&func_mutex); \
126 if (!_close) \
127 _close = (int (*)(int)) dlsym(RTLD_NEXT, "close"); \
128 pthread_mutex_unlock(&func_mutex); \
129 } while(0)
130
131 #define LOAD_FOPEN_FUNC() \
132 do { \
133 pthread_mutex_lock(&func_mutex); \
134 if (!_fopen) \
135 _fopen = (FILE* (*)(const char *, const char*)) dlsym(RTLD_NEXT, "fopen"); \
136 pthread_mutex_unlock(&func_mutex); \
137 } while(0)
138
139 #define LOAD_FOPEN64_FUNC() \
140 do { \
141 pthread_mutex_lock(&func_mutex); \
142 if (!_fopen64) \
143 _fopen64 = (FILE* (*)(const char *, const char*)) dlsym(RTLD_NEXT, "fopen64"); \
144 pthread_mutex_unlock(&func_mutex); \
145 } while(0)
146
147 #define LOAD_FCLOSE_FUNC() \
148 do { \
149 pthread_mutex_lock(&func_mutex); \
150 if (!_fclose) \
151 _fclose = (int (*)(FILE *)) dlsym(RTLD_NEXT, "fclose"); \
152 pthread_mutex_unlock(&func_mutex); \
153 } while(0)
154
155 static void debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2);
156
157 static void debug(const char *format, ...) {
158 va_list ap;
159 if (getenv("PADSP_DEBUG")) {
160 va_start(ap, format);
161 vfprintf(stderr, format, ap);
162 va_end(ap);
163 }
164 }
165
166 static pthread_key_t recursion_key;
167
168 static void recursion_key_alloc(void) {
169 pthread_key_create(&recursion_key, NULL);
170 }
171
172 static int function_enter(void) {
173 /* Avoid recursive calls */
174 static pthread_once_t recursion_key_once = PTHREAD_ONCE_INIT;
175 pthread_once(&recursion_key_once, recursion_key_alloc);
176
177 if (pthread_getspecific(recursion_key))
178 return 0;
179
180 pthread_setspecific(recursion_key, (void*) 1);
181 return 1;
182 }
183
184 static void function_exit(void) {
185 pthread_setspecific(recursion_key, NULL);
186 }
187
188 static void fd_info_free(fd_info *i) {
189 assert(i);
190
191 debug(__FILE__": freeing fd info (fd=%i)\n", i->app_fd);
192
193 dsp_drain(i);
194
195 if (i->mainloop)
196 pa_threaded_mainloop_stop(i->mainloop);
197
198 if (i->stream) {
199 pa_stream_disconnect(i->stream);
200 pa_stream_unref(i->stream);
201 }
202
203 if (i->context) {
204 pa_context_disconnect(i->context);
205 pa_context_unref(i->context);
206 }
207
208 if (i->mainloop)
209 pa_threaded_mainloop_free(i->mainloop);
210
211 if (i->app_fd >= 0) {
212 LOAD_CLOSE_FUNC();
213 _close(i->app_fd);
214 }
215
216 if (i->thread_fd >= 0) {
217 LOAD_CLOSE_FUNC();
218 _close(i->thread_fd);
219 }
220
221 free(i->buf);
222
223 pthread_mutex_destroy(&i->mutex);
224 free(i);
225 }
226
227 static fd_info *fd_info_ref(fd_info *i) {
228 assert(i);
229
230 pthread_mutex_lock(&i->mutex);
231 assert(i->ref >= 1);
232 i->ref++;
233
234 /* debug(__FILE__": ref++, now %i\n", i->ref); */
235 pthread_mutex_unlock(&i->mutex);
236
237 return i;
238 }
239
240 static void fd_info_unref(fd_info *i) {
241 int r;
242 pthread_mutex_lock(&i->mutex);
243 assert(i->ref >= 1);
244 r = --i->ref;
245 /* debug(__FILE__": ref--, now %i\n", i->ref); */
246 pthread_mutex_unlock(&i->mutex);
247
248 if (r <= 0)
249 fd_info_free(i);
250 }
251
252 static void context_state_cb(pa_context *c, void *userdata) {
253 fd_info *i = userdata;
254 assert(c);
255
256 switch (pa_context_get_state(c)) {
257 case PA_CONTEXT_READY:
258 case PA_CONTEXT_TERMINATED:
259 case PA_CONTEXT_FAILED:
260 pa_threaded_mainloop_signal(i->mainloop, 0);
261 break;
262
263 case PA_CONTEXT_UNCONNECTED:
264 case PA_CONTEXT_CONNECTING:
265 case PA_CONTEXT_AUTHORIZING:
266 case PA_CONTEXT_SETTING_NAME:
267 break;
268 }
269 }
270
271 static void reset_params(fd_info *i) {
272 assert(i);
273
274 i->sample_spec.format = PA_SAMPLE_ULAW;
275 i->sample_spec.channels = 1;
276 i->sample_spec.rate = 8000;
277 i->fragment_size = 1024;
278 i->n_fragments = 0;
279 }
280
281 static fd_info* fd_info_new(fd_info_type_t type, int *_errno) {
282 fd_info *i;
283 int sfds[2] = { -1, -1 };
284
285 debug(__FILE__": fd_info_new()\n");
286
287 signal(SIGPIPE, SIG_IGN); /* Yes, ugly as hell */
288
289 if (!(i = malloc(sizeof(fd_info)))) {
290 *_errno = ENOMEM;
291 goto fail;
292 }
293
294 i->app_fd = i->thread_fd = -1;
295 i->type = type;
296
297 i->mainloop = NULL;
298 i->context = NULL;
299 i->stream = NULL;
300 i->io_event = NULL;
301 pthread_mutex_init(&i->mutex, NULL);
302 i->ref = 1;
303 i->buf = NULL;
304 PA_LLIST_INIT(fd_info, i);
305
306 reset_params(i);
307
308 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfds) < 0) {
309 *_errno = errno;
310 debug(__FILE__": socket() failed: %s\n", strerror(errno));
311 goto fail;
312 }
313
314 i->app_fd = sfds[0];
315 i->thread_fd = sfds[1];
316
317 if (!(i->mainloop = pa_threaded_mainloop_new())) {
318 *_errno = EIO;
319 debug(__FILE__": pa_threaded_mainloop_new() failed\n");
320 goto fail;
321 }
322
323 if (!(i->context = pa_context_new(pa_threaded_mainloop_get_api(i->mainloop), "oss"))) {
324 *_errno = EIO;
325 debug(__FILE__": pa_context_new() failed\n");
326 goto fail;
327 }
328
329 pa_context_set_state_callback(i->context, context_state_cb, i);
330
331 if (pa_context_connect(i->context, NULL, 0, NULL) < 0) {
332 *_errno = ECONNREFUSED;
333 debug(__FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
334 goto fail;
335 }
336
337 pa_threaded_mainloop_lock(i->mainloop);
338
339 if (pa_threaded_mainloop_start(i->mainloop) < 0) {
340 *_errno = EIO;
341 debug(__FILE__": pa_threaded_mainloop_start() failed\n");
342 goto unlock_and_fail;
343 }
344
345 /* Wait until the context is ready */
346 pa_threaded_mainloop_wait(i->mainloop);
347
348 if (pa_context_get_state(i->context) != PA_CONTEXT_READY) {
349 *_errno = ECONNREFUSED;
350 debug(__FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
351 goto unlock_and_fail;
352 }
353
354 pa_threaded_mainloop_unlock(i->mainloop);
355 return i;
356
357 unlock_and_fail:
358
359 pa_threaded_mainloop_unlock(i->mainloop);
360
361 fail:
362
363 if (i)
364 fd_info_unref(i);
365
366 return NULL;
367 }
368
369 static void fd_info_add_to_list(fd_info *i) {
370 assert(i);
371
372 pthread_mutex_lock(&fd_infos_mutex);
373 PA_LLIST_PREPEND(fd_info, fd_infos, i);
374 pthread_mutex_unlock(&fd_infos_mutex);
375
376 fd_info_ref(i);
377 }
378
379 static void fd_info_remove_from_list(fd_info *i) {
380 assert(i);
381
382 pthread_mutex_lock(&fd_infos_mutex);
383 PA_LLIST_REMOVE(fd_info, fd_infos, i);
384 pthread_mutex_unlock(&fd_infos_mutex);
385
386 fd_info_unref(i);
387 }
388
389 static fd_info* fd_info_find(int fd) {
390 fd_info *i;
391
392 pthread_mutex_lock(&fd_infos_mutex);
393
394 for (i = fd_infos; i; i = i->next)
395 if (i->app_fd == fd) {
396 fd_info_ref(i);
397 break;
398 }
399
400 pthread_mutex_unlock(&fd_infos_mutex);
401
402 return i;
403 }
404
405 static void fix_metrics(fd_info *i) {
406 size_t fs;
407 char t[PA_SAMPLE_SPEC_SNPRINT_MAX];
408
409 fs = pa_frame_size(&i->sample_spec);
410 i->fragment_size = (i->fragment_size/fs)*fs;
411
412 if (i->n_fragments < 2)
413 i->n_fragments = 12;
414
415 if (i->fragment_size <= 0)
416 if ((i->fragment_size = pa_bytes_per_second(&i->sample_spec) / 2 / i->n_fragments) <= 0)
417 i->fragment_size = 1024;
418
419 debug(__FILE__": sample spec: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec));
420 debug(__FILE__": fixated metrics to %i fragments, %li bytes each.\n", i->n_fragments, (long)i->fragment_size);
421 }
422
423 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
424 fd_info *i = userdata;
425 assert(s);
426
427 if (i->io_event) {
428 pa_mainloop_api *api;
429 api = pa_threaded_mainloop_get_api(i->mainloop);
430 api->io_enable(i->io_event, PA_IO_EVENT_INPUT);
431 }
432 }
433
434 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
435 fd_info *i = userdata;
436 assert(s);
437
438 pa_threaded_mainloop_signal(i->mainloop, 0);
439 }
440
441 static void fd_info_shutdown(fd_info *i) {
442 assert(i);
443
444 if (i->io_event) {
445 pa_mainloop_api *api;
446 api = pa_threaded_mainloop_get_api(i->mainloop);
447 api->io_free(i->io_event);
448 i->io_event = NULL;
449 }
450
451 if (i->thread_fd >= 0) {
452 close(i->thread_fd);
453 i->thread_fd = -1;
454 }
455 }
456
457 static int fd_info_copy_data(fd_info *i, int force) {
458 size_t n;
459
460 if (!i->stream)
461 return -1;
462
463 if ((n = pa_stream_writable_size(i->stream)) == (size_t) -1) {
464 debug(__FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context)));
465 return -1;
466 }
467
468 while (n >= i->fragment_size || force) {
469 ssize_t r;
470
471 if (!i->buf) {
472 if (!(i->buf = malloc(i->fragment_size))) {
473 debug(__FILE__": malloc() failed.\n");
474 return -1;
475 }
476 }
477
478 if ((r = read(i->thread_fd, i->buf, i->fragment_size)) <= 0) {
479
480 if (errno == EAGAIN)
481 break;
482
483 debug(__FILE__": read(): %s\n", r == 0 ? "EOF" : strerror(errno));
484 return -1;
485 }
486
487 if (pa_stream_write(i->stream, i->buf, r, free, 0, PA_SEEK_RELATIVE) < 0) {
488 debug(__FILE__": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i->context)));
489 return -1;
490 }
491
492 i->buf = NULL;
493
494 assert(n >= (size_t) r);
495 n -= r;
496 }
497
498 if (i->io_event) {
499 pa_mainloop_api *api;
500 api = pa_threaded_mainloop_get_api(i->mainloop);
501 api->io_enable(i->io_event, n >= i->fragment_size ? PA_IO_EVENT_INPUT : 0);
502 }
503
504 return 0;
505 }
506
507 static void stream_state_cb(pa_stream *s, void * userdata) {
508 fd_info *i = userdata;
509 assert(s);
510
511 switch (pa_stream_get_state(s)) {
512
513 case PA_STREAM_READY:
514 debug(__FILE__": stream established.\n");
515 break;
516
517 case PA_STREAM_FAILED:
518 debug(__FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
519 fd_info_shutdown(i);
520 break;
521
522 case PA_STREAM_TERMINATED:
523 case PA_STREAM_UNCONNECTED:
524 case PA_STREAM_CREATING:
525 break;
526 }
527 }
528
529 static int create_stream(fd_info *i) {
530 pa_buffer_attr attr;
531 int n;
532
533 assert(i);
534
535 fix_metrics(i);
536
537 if (!(i->stream = pa_stream_new(i->context, "audio stream", &i->sample_spec, NULL))) {
538 debug(__FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
539 goto fail;
540 }
541
542 pa_stream_set_state_callback(i->stream, stream_state_cb, i);
543 pa_stream_set_write_callback(i->stream, stream_request_cb, i);
544 pa_stream_set_latency_update_callback(i->stream, stream_latency_update_cb, i);
545
546 memset(&attr, 0, sizeof(attr));
547 attr.maxlength = i->fragment_size * (i->n_fragments+1);
548 attr.tlength = i->fragment_size * i->n_fragments;
549 attr.prebuf = i->fragment_size;
550 attr.minreq = i->fragment_size;
551
552 if (pa_stream_connect_playback(i->stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) {
553 debug(__FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
554 goto fail;
555 }
556
557 n = i->fragment_size;
558 setsockopt(i->app_fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n));
559 n = i->fragment_size;
560 setsockopt(i->thread_fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));
561
562 return 0;
563
564 fail:
565 return -1;
566 }
567
568 static void free_stream(fd_info *i) {
569 assert(i);
570
571 if (i->stream) {
572 pa_stream_disconnect(i->stream);
573 pa_stream_unref(i->stream);
574 i->stream = NULL;
575 }
576 }
577
578 static void io_event_cb(pa_mainloop_api *api, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) {
579 fd_info *i = userdata;
580
581 pa_threaded_mainloop_signal(i->mainloop, 0);
582
583 if (flags & PA_IO_EVENT_INPUT) {
584
585 if (!i->stream) {
586 api->io_enable(e, 0);
587
588 if (create_stream(i) < 0)
589 goto fail;
590
591 } else {
592 if (fd_info_copy_data(i, 0) < 0)
593 goto fail;
594 }
595
596 } else if (flags & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR))
597 goto fail;
598
599 return;
600
601 fail:
602 /* We can't do anything better than removing the event source */
603 fd_info_shutdown(i);
604 }
605
606 static int dsp_open(int flags, int *_errno) {
607 fd_info *i;
608 pa_mainloop_api *api;
609 int ret;
610 int f;
611
612 if ((flags != O_WRONLY) && (flags != (O_WRONLY|O_NONBLOCK))) {
613 *_errno = EACCES;
614 return -1;
615 }
616
617 if (!(i = fd_info_new(FD_INFO_PLAYBACK, _errno)))
618 return -1;
619
620 shutdown(i->thread_fd, SHUT_WR);
621 shutdown(i->app_fd, SHUT_RD);
622
623 if ((flags & O_NONBLOCK) == O_NONBLOCK) {
624 if ((f = fcntl(i->app_fd, F_GETFL)) >= 0)
625 fcntl(i->app_fd, F_SETFL, f|O_NONBLOCK);
626 }
627 if ((f = fcntl(i->thread_fd, F_GETFL)) >= 0)
628 fcntl(i->thread_fd, F_SETFL, f|O_NONBLOCK);
629
630 fcntl(i->app_fd, F_SETFD, FD_CLOEXEC);
631 fcntl(i->thread_fd, F_SETFD, FD_CLOEXEC);
632
633 pa_threaded_mainloop_lock(i->mainloop);
634 api = pa_threaded_mainloop_get_api(i->mainloop);
635 if (!(i->io_event = api->io_new(api, i->thread_fd, PA_IO_EVENT_INPUT, io_event_cb, i)))
636 goto fail;
637
638 pa_threaded_mainloop_unlock(i->mainloop);
639
640 debug(__FILE__": dsp_open() succeeded, fd=%i\n", i->app_fd);
641
642 fd_info_add_to_list(i);
643 ret = i->app_fd;
644 fd_info_unref(i);
645
646 return ret;
647
648 fail:
649 pa_threaded_mainloop_unlock(i->mainloop);
650
651 if (i)
652 fd_info_unref(i);
653
654 *_errno = EIO;
655
656 debug(__FILE__": dsp_open() failed\n");
657
658 return -1;
659 }
660
661 static int mixer_open(int flags, int *_errno) {
662 /* fd_info *i; */
663
664 *_errno = ENOSYS;
665 return -1;
666
667 /* if (!(i = fd_info_new(FD_INFO_MIXER))) */
668 /* return -1; */
669
670 }
671
672 int open(const char *filename, int flags, ...) {
673 va_list args;
674 mode_t mode = 0;
675 int r, _errno = 0;
676
677 va_start(args, flags);
678 if (flags & O_CREAT)
679 mode = va_arg(args, mode_t);
680 va_end(args);
681
682 if (!function_enter()) {
683 LOAD_OPEN_FUNC();
684 return _open(filename, flags, mode);
685 }
686
687 debug(__FILE__": open()\n");
688
689 if (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0) {
690 r = dsp_open(flags, &_errno);
691 } else if (strcmp(filename, "/dev/mixer") == 0) {
692 r = mixer_open(flags, &_errno);
693 } else {
694 function_exit();
695 LOAD_OPEN_FUNC();
696 return _open(filename, flags, mode);
697 }
698
699 function_exit();
700
701 if (_errno)
702 errno = _errno;
703
704 return r;
705 }
706
707 static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) {
708 *_errno = ENOSYS;
709 return -1;
710 }
711
712 static int map_format(int *fmt, pa_sample_spec *ss) {
713
714 switch (*fmt) {
715 case AFMT_MU_LAW:
716 ss->format = PA_SAMPLE_ULAW;
717 break;
718
719 case AFMT_A_LAW:
720 ss->format = PA_SAMPLE_ALAW;
721 break;
722
723 case AFMT_S8:
724 *fmt = AFMT_U8;
725 /* fall through */
726 case AFMT_U8:
727 ss->format = PA_SAMPLE_U8;
728 break;
729
730 case AFMT_U16_BE:
731 *fmt = AFMT_S16_BE;
732 /* fall through */
733 case AFMT_S16_BE:
734 ss->format = PA_SAMPLE_S16BE;
735 break;
736
737 case AFMT_U16_LE:
738 *fmt = AFMT_S16_LE;
739 /* fall through */
740 case AFMT_S16_LE:
741 ss->format = PA_SAMPLE_S16LE;
742 break;
743
744 default:
745 ss->format = PA_SAMPLE_S16NE;
746 *fmt = AFMT_S16_NE;
747 break;
748 }
749
750 return 0;
751 }
752
753 static int map_format_back(pa_sample_format_t format) {
754 switch (format) {
755 case PA_SAMPLE_S16LE: return AFMT_S16_LE;
756 case PA_SAMPLE_S16BE: return AFMT_S16_BE;
757 case PA_SAMPLE_ULAW: return AFMT_MU_LAW;
758 case PA_SAMPLE_ALAW: return AFMT_A_LAW;
759 case PA_SAMPLE_U8: return AFMT_U8;
760 default:
761 abort();
762 }
763 }
764
765 static void success_cb(pa_stream *s, int success, void *userdata) {
766 fd_info *i = userdata;
767
768 assert(s);
769 assert(i);
770
771 i->operation_success = success;
772 pa_threaded_mainloop_signal(i->mainloop, 0);
773 }
774
775 static int dsp_empty_socket(fd_info *i) {
776 int ret = -1;
777
778 /* Empty the socket */
779 for (;;) {
780 int l;
781
782 if (i->thread_fd < 0)
783 break;
784
785 if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) {
786 debug(__FILE__": SIOCINQ: %s\n", strerror(errno));
787 break;
788 }
789
790 if (!l)
791 break;
792
793 pa_threaded_mainloop_wait(i->mainloop);
794 }
795
796 return ret;
797 }
798
799 static int dsp_drain(fd_info *i) {
800 pa_operation *o = NULL;
801 int r = -1;
802
803 if (!i->mainloop)
804 return 0;
805
806 debug(__FILE__": Draining.\n");
807
808 pa_threaded_mainloop_lock(i->mainloop);
809
810 if (dsp_empty_socket(i) < 0)
811 goto fail;
812
813 if (!i->stream)
814 goto fail;
815
816 debug(__FILE__": Really draining.\n");
817
818 if (!(o = pa_stream_drain(i->stream, success_cb, i))) {
819 debug(__FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context)));
820 goto fail;
821 }
822
823 i->operation_success = 0;
824 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
825 if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY)
826 goto fail;
827
828 pa_threaded_mainloop_wait(i->mainloop);
829 }
830
831 if (!i->operation_success) {
832 debug(__FILE__": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i->context)));
833 goto fail;
834 }
835
836 r = 0;
837
838 fail:
839
840 if (o)
841 pa_operation_unref(o);
842
843 pa_threaded_mainloop_unlock(i->mainloop);
844
845 return 0;
846 }
847
848 static int dsp_trigger(fd_info *i) {
849 pa_operation *o = NULL;
850 int r = -1;
851
852 fd_info_copy_data(i, 1);
853
854 if (!i->stream)
855 return 0;
856
857 pa_threaded_mainloop_lock(i->mainloop);
858
859 if (dsp_empty_socket(i) < 0)
860 goto fail;
861
862 debug(__FILE__": Triggering.\n");
863
864 if (!(o = pa_stream_trigger(i->stream, success_cb, i))) {
865 debug(__FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context)));
866 goto fail;
867 }
868
869 i->operation_success = 0;
870 while (!pa_operation_get_state(o) != PA_OPERATION_DONE) {
871 if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY)
872 goto fail;
873
874 pa_threaded_mainloop_wait(i->mainloop);
875 }
876
877 if (!i->operation_success) {
878 debug(__FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context)));
879 goto fail;
880 }
881
882 r = 0;
883
884 fail:
885
886 if (o)
887 pa_operation_unref(o);
888
889 pa_threaded_mainloop_unlock(i->mainloop);
890
891 return 0;
892 }
893
894 static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) {
895 int ret = -1;
896
897 switch (request) {
898 case SNDCTL_DSP_SETFMT: {
899 debug(__FILE__": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp);
900
901 pa_threaded_mainloop_lock(i->mainloop);
902
903 if (*(int*) argp == AFMT_QUERY)
904 *(int*) argp = map_format_back(i->sample_spec.format);
905 else {
906 map_format((int*) argp, &i->sample_spec);
907 free_stream(i);
908 }
909
910 pa_threaded_mainloop_unlock(i->mainloop);
911 break;
912 }
913
914 case SNDCTL_DSP_SPEED: {
915 pa_sample_spec ss;
916 int valid;
917
918 debug(__FILE__": SNDCTL_DSP_SPEED: %i\n", *(int*) argp);
919
920 pa_threaded_mainloop_lock(i->mainloop);
921
922 ss = i->sample_spec;
923 ss.rate = *(int*) argp;
924
925 if ((valid = pa_sample_spec_valid(&ss))) {
926 i->sample_spec = ss;
927 free_stream(i);
928 }
929
930 pa_threaded_mainloop_unlock(i->mainloop);
931
932 if (!valid) {
933 *_errno = EINVAL;
934 goto fail;
935 }
936
937 break;
938 }
939
940 case SNDCTL_DSP_STEREO:
941 debug(__FILE__": SNDCTL_DSP_STEREO: %i\n", *(int*) argp);
942
943 pa_threaded_mainloop_lock(i->mainloop);
944
945 i->sample_spec.channels = *(int*) argp ? 2 : 1;
946 free_stream(i);
947
948 pa_threaded_mainloop_unlock(i->mainloop);
949 return 0;
950
951 case SNDCTL_DSP_CHANNELS: {
952 pa_sample_spec ss;
953 int valid;
954
955 debug(__FILE__": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp);
956
957 pa_threaded_mainloop_lock(i->mainloop);
958
959 ss = i->sample_spec;
960 ss.channels = *(int*) argp;
961
962 if ((valid = pa_sample_spec_valid(&ss))) {
963 i->sample_spec = ss;
964 free_stream(i);
965 }
966
967 pa_threaded_mainloop_unlock(i->mainloop);
968
969 if (!valid) {
970 *_errno = EINVAL;
971 goto fail;
972 }
973
974 break;
975 }
976
977 case SNDCTL_DSP_GETBLKSIZE:
978 debug(__FILE__": SNDCTL_DSP_GETBLKSIZE\n");
979
980 pa_threaded_mainloop_lock(i->mainloop);
981
982 fix_metrics(i);
983 *(int*) argp = i->fragment_size;
984
985 pa_threaded_mainloop_unlock(i->mainloop);
986
987 break;
988
989 case SNDCTL_DSP_SETFRAGMENT:
990 debug(__FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%8x\n", *(int*) argp);
991
992 pa_threaded_mainloop_lock(i->mainloop);
993
994 i->fragment_size = 1 << (*(int*) argp);
995 i->n_fragments = (*(int*) argp) >> 16;
996
997 free_stream(i);
998
999 pa_threaded_mainloop_unlock(i->mainloop);
1000
1001 break;
1002
1003 case SNDCTL_DSP_GETCAPS:
1004 debug(__FILE__": SNDCTL_DSP_CAPS\n");
1005
1006 *(int*) argp = DSP_CAP_MULTI;
1007 break;
1008
1009 case SNDCTL_DSP_GETODELAY: {
1010 int l;
1011
1012 debug(__FILE__": SNDCTL_DSP_GETODELAY\n");
1013
1014 pa_threaded_mainloop_lock(i->mainloop);
1015
1016 *(int*) argp = 0;
1017
1018 for (;;) {
1019 pa_usec_t usec;
1020 if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY)
1021 break;
1022
1023 if (pa_stream_get_latency(i->stream, &usec, NULL) >= 0) {
1024 *(int*) argp = pa_usec_to_bytes(usec, &i->sample_spec);
1025 break;
1026 }
1027
1028 if (pa_context_errno(i->context) != PA_ERR_NODATA) {
1029 debug(__FILE__": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i->context)));
1030 break;
1031 }
1032
1033 pa_threaded_mainloop_wait(i->mainloop);
1034 }
1035
1036 if (ioctl(i->thread_fd, SIOCINQ, &l) < 0)
1037 debug(__FILE__": SIOCINQ failed: %s\n", strerror(errno));
1038 else
1039 *(int*) argp += l;
1040
1041 pa_threaded_mainloop_unlock(i->mainloop);
1042
1043 debug(__FILE__": ODELAY: %i\n", *(int*) argp);
1044
1045 break;
1046 }
1047
1048 case SNDCTL_DSP_RESET: {
1049 debug(__FILE__": SNDCTL_DSP_RESET\n");
1050
1051 pa_threaded_mainloop_lock(i->mainloop);
1052
1053 free_stream(i);
1054 reset_params(i);
1055
1056 pa_threaded_mainloop_unlock(i->mainloop);
1057 break;
1058 }
1059
1060 case SNDCTL_DSP_GETFMTS: {
1061 debug(__FILE__": SNDCTL_DSP_GETFMTS\n");
1062
1063 *(int*) argp = AFMT_MU_LAW|AFMT_A_LAW|AFMT_U8|AFMT_S16_LE|AFMT_S16_BE;
1064 break;
1065 }
1066
1067 case SNDCTL_DSP_POST:
1068 debug(__FILE__": SNDCTL_DSP_POST\n");
1069
1070 if (dsp_trigger(i) < 0)
1071 *_errno = EIO;
1072 break;
1073
1074 case SNDCTL_DSP_SYNC:
1075 debug(__FILE__": SNDCTL_DSP_SYNC\n");
1076
1077 if (dsp_drain(i) < 0)
1078 *_errno = EIO;
1079
1080 break;
1081
1082 case SNDCTL_DSP_GETOSPACE: {
1083 audio_buf_info *bi = (audio_buf_info*) argp;
1084 int l;
1085 size_t k = 0;
1086
1087 debug(__FILE__": SNDCTL_DSP_GETOSPACE\n");
1088
1089 pa_threaded_mainloop_lock(i->mainloop);
1090
1091 fix_metrics(i);
1092
1093 if (i->stream) {
1094 if ((k = pa_stream_writable_size(i->stream)) == (size_t) -1)
1095 debug(__FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context)));
1096 } else
1097 k = i->fragment_size * i->n_fragments;
1098
1099 if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) {
1100 debug(__FILE__": SIOCINQ failed: %s\n", strerror(errno));
1101 l = 0;
1102 }
1103
1104 bi->fragsize = i->fragment_size;
1105 bi->fragstotal = i->n_fragments;
1106 bi->bytes = k > (size_t) l ? k - l : 0;
1107 bi->fragments = bi->bytes / bi->fragsize;
1108
1109 pa_threaded_mainloop_unlock(i->mainloop);
1110
1111 debug(__FILE__": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi->fragsize, bi->fragstotal, bi->bytes, bi->fragments);
1112
1113 break;
1114 }
1115
1116 default:
1117 debug(__FILE__": unknwon ioctl 0x%08lx\n", request);
1118
1119 *_errno = EINVAL;
1120 goto fail;
1121 }
1122
1123 ret = 0;
1124
1125 fail:
1126
1127 return ret;
1128 }
1129
1130 int ioctl(int fd, unsigned long request, ...) {
1131 fd_info *i;
1132 va_list args;
1133 void *argp;
1134 int r, _errno = 0;
1135
1136 debug(__FILE__": ioctl()\n");
1137
1138 va_start(args, request);
1139 argp = va_arg(args, void *);
1140 va_end(args);
1141
1142 if (!function_enter()) {
1143 LOAD_IOCTL_FUNC();
1144 return _ioctl(fd, request, argp);
1145 }
1146
1147 if (!(i = fd_info_find(fd))) {
1148 function_exit();
1149 LOAD_IOCTL_FUNC();
1150 return _ioctl(fd, request, argp);
1151 }
1152
1153 if (i->type == FD_INFO_MIXER)
1154 r = mixer_ioctl(i, request, argp, &_errno);
1155 else
1156 r = dsp_ioctl(i, request, argp, &_errno);
1157
1158 fd_info_unref(i);
1159
1160 if (_errno)
1161 errno = _errno;
1162
1163 function_exit();
1164
1165 return r;
1166 }
1167
1168 int close(int fd) {
1169 fd_info *i;
1170
1171 debug(__FILE__": close()\n");
1172
1173 if (!function_enter()) {
1174 LOAD_CLOSE_FUNC();
1175 return _close(fd);
1176 }
1177
1178 if (!(i = fd_info_find(fd))) {
1179 function_exit();
1180 LOAD_CLOSE_FUNC();
1181 return _close(fd);
1182 }
1183
1184 fd_info_remove_from_list(i);
1185 fd_info_unref(i);
1186
1187 function_exit();
1188
1189 return 0;
1190 }
1191
1192 int open64(const char *filename, int flags, ...) {
1193 va_list args;
1194 mode_t mode = 0;
1195
1196 debug(__FILE__": open64()\n");
1197
1198 va_start(args, flags);
1199 if (flags & O_CREAT)
1200 mode = va_arg(args, mode_t);
1201 va_end(args);
1202
1203 if (strcmp(filename, "/dev/dsp") != 0 &&
1204 strcmp(filename, "/dev/adsp") != 0 &&
1205 strcmp(filename, "/dev/mixer") != 0) {
1206 LOAD_OPEN64_FUNC();
1207 return _open64(filename, flags, mode);
1208 }
1209
1210 return open(filename, flags, mode);
1211 }
1212
1213 FILE* fopen(const char *filename, const char *mode) {
1214 FILE *f = NULL;
1215 int fd;
1216
1217 debug(__FILE__": fopen()\n");
1218
1219 if (strcmp(filename, "/dev/dsp") != 0 &&
1220 strcmp(filename, "/dev/adsp") != 0 &&
1221 strcmp(filename, "/dev/mixer") != 0) {
1222 LOAD_FOPEN_FUNC();
1223 return _fopen(filename, mode);
1224 }
1225
1226 if (strcmp(mode, "wb") != 0) {
1227 errno = EACCES;
1228 return NULL;
1229 }
1230
1231 if ((fd = open(filename, O_WRONLY)) < 0)
1232 return NULL;
1233
1234 if (!(f = fdopen(fd, "wb"))) {
1235 close(fd);
1236 return NULL;
1237 }
1238
1239 return f;
1240 }
1241
1242 FILE *fopen64(const char *filename, const char *mode) {
1243
1244 debug(__FILE__": fopen64()\n");
1245
1246 if (strcmp(filename, "/dev/dsp") != 0 &&
1247 strcmp(filename, "/dev/adsp") != 0 &&
1248 strcmp(filename, "/dev/mixer") != 0) {
1249 LOAD_FOPEN64_FUNC();
1250 return _fopen64(filename, mode);
1251 }
1252
1253 return fopen(filename, mode);
1254 }
1255
1256 int fclose(FILE *f) {
1257 fd_info *i;
1258
1259 debug(__FILE__": fclose()\n");
1260
1261 if (!function_enter()) {
1262 LOAD_FCLOSE_FUNC();
1263 return _fclose(f);
1264 }
1265
1266 if (!(i = fd_info_find(fileno(f)))) {
1267 function_exit();
1268 LOAD_FCLOSE_FUNC();
1269 return _fclose(f);
1270 }
1271
1272 fd_info_remove_from_list(i);
1273
1274 /* Dirty trick to avoid that the fd is not freed twice, once by us
1275 * and once by the real fclose() */
1276 i->app_fd = -1;
1277
1278 fd_info_unref(i);
1279
1280 function_exit();
1281
1282 LOAD_FCLOSE_FUNC();
1283 return _fclose(f);
1284 }