]> code.delx.au - pulseaudio/blob - src/utils/padsp.c
pass the binary name as client name to polypaudio
[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 char *client_name(char *buf, size_t n) {
282 char p[PATH_MAX];
283
284 if (pa_get_binary_name(p, sizeof(p)))
285 snprintf(buf, n, "oss[%s]", pa_path_get_filename(p));
286 else
287 snprintf(buf, n, "oss");
288
289 return buf;
290 }
291
292 static fd_info* fd_info_new(fd_info_type_t type, int *_errno) {
293 fd_info *i;
294 int sfds[2] = { -1, -1 };
295 char name[64];
296
297 debug(__FILE__": fd_info_new()\n");
298
299 signal(SIGPIPE, SIG_IGN); /* Yes, ugly as hell */
300
301 if (!(i = malloc(sizeof(fd_info)))) {
302 *_errno = ENOMEM;
303 goto fail;
304 }
305
306 i->app_fd = i->thread_fd = -1;
307 i->type = type;
308
309 i->mainloop = NULL;
310 i->context = NULL;
311 i->stream = NULL;
312 i->io_event = NULL;
313 pthread_mutex_init(&i->mutex, NULL);
314 i->ref = 1;
315 i->buf = NULL;
316 PA_LLIST_INIT(fd_info, i);
317
318 reset_params(i);
319
320 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfds) < 0) {
321 *_errno = errno;
322 debug(__FILE__": socket() failed: %s\n", strerror(errno));
323 goto fail;
324 }
325
326 i->app_fd = sfds[0];
327 i->thread_fd = sfds[1];
328
329 if (!(i->mainloop = pa_threaded_mainloop_new())) {
330 *_errno = EIO;
331 debug(__FILE__": pa_threaded_mainloop_new() failed\n");
332 goto fail;
333 }
334
335 if (!(i->context = pa_context_new(pa_threaded_mainloop_get_api(i->mainloop), client_name(name, sizeof(name))))) {
336 *_errno = EIO;
337 debug(__FILE__": pa_context_new() failed\n");
338 goto fail;
339 }
340
341 pa_context_set_state_callback(i->context, context_state_cb, i);
342
343 if (pa_context_connect(i->context, NULL, 0, NULL) < 0) {
344 *_errno = ECONNREFUSED;
345 debug(__FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
346 goto fail;
347 }
348
349 pa_threaded_mainloop_lock(i->mainloop);
350
351 if (pa_threaded_mainloop_start(i->mainloop) < 0) {
352 *_errno = EIO;
353 debug(__FILE__": pa_threaded_mainloop_start() failed\n");
354 goto unlock_and_fail;
355 }
356
357 /* Wait until the context is ready */
358 pa_threaded_mainloop_wait(i->mainloop);
359
360 if (pa_context_get_state(i->context) != PA_CONTEXT_READY) {
361 *_errno = ECONNREFUSED;
362 debug(__FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
363 goto unlock_and_fail;
364 }
365
366 pa_threaded_mainloop_unlock(i->mainloop);
367 return i;
368
369 unlock_and_fail:
370
371 pa_threaded_mainloop_unlock(i->mainloop);
372
373 fail:
374
375 if (i)
376 fd_info_unref(i);
377
378 return NULL;
379 }
380
381 static void fd_info_add_to_list(fd_info *i) {
382 assert(i);
383
384 pthread_mutex_lock(&fd_infos_mutex);
385 PA_LLIST_PREPEND(fd_info, fd_infos, i);
386 pthread_mutex_unlock(&fd_infos_mutex);
387
388 fd_info_ref(i);
389 }
390
391 static void fd_info_remove_from_list(fd_info *i) {
392 assert(i);
393
394 pthread_mutex_lock(&fd_infos_mutex);
395 PA_LLIST_REMOVE(fd_info, fd_infos, i);
396 pthread_mutex_unlock(&fd_infos_mutex);
397
398 fd_info_unref(i);
399 }
400
401 static fd_info* fd_info_find(int fd) {
402 fd_info *i;
403
404 pthread_mutex_lock(&fd_infos_mutex);
405
406 for (i = fd_infos; i; i = i->next)
407 if (i->app_fd == fd) {
408 fd_info_ref(i);
409 break;
410 }
411
412 pthread_mutex_unlock(&fd_infos_mutex);
413
414 return i;
415 }
416
417 static void fix_metrics(fd_info *i) {
418 size_t fs;
419 char t[PA_SAMPLE_SPEC_SNPRINT_MAX];
420
421 fs = pa_frame_size(&i->sample_spec);
422 i->fragment_size = (i->fragment_size/fs)*fs;
423
424 if (i->n_fragments < 2)
425 i->n_fragments = 12;
426
427 if (i->fragment_size <= 0)
428 if ((i->fragment_size = pa_bytes_per_second(&i->sample_spec) / 2 / i->n_fragments) <= 0)
429 i->fragment_size = 1024;
430
431 debug(__FILE__": sample spec: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec));
432 debug(__FILE__": fixated metrics to %i fragments, %li bytes each.\n", i->n_fragments, (long)i->fragment_size);
433 }
434
435 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
436 fd_info *i = userdata;
437 assert(s);
438
439 if (i->io_event) {
440 pa_mainloop_api *api;
441 api = pa_threaded_mainloop_get_api(i->mainloop);
442 api->io_enable(i->io_event, PA_IO_EVENT_INPUT);
443 }
444 }
445
446 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
447 fd_info *i = userdata;
448 assert(s);
449
450 pa_threaded_mainloop_signal(i->mainloop, 0);
451 }
452
453 static void fd_info_shutdown(fd_info *i) {
454 assert(i);
455
456 if (i->io_event) {
457 pa_mainloop_api *api;
458 api = pa_threaded_mainloop_get_api(i->mainloop);
459 api->io_free(i->io_event);
460 i->io_event = NULL;
461 }
462
463 if (i->thread_fd >= 0) {
464 close(i->thread_fd);
465 i->thread_fd = -1;
466 }
467 }
468
469 static int fd_info_copy_data(fd_info *i, int force) {
470 size_t n;
471
472 if (!i->stream)
473 return -1;
474
475 if ((n = pa_stream_writable_size(i->stream)) == (size_t) -1) {
476 debug(__FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context)));
477 return -1;
478 }
479
480 while (n >= i->fragment_size || force) {
481 ssize_t r;
482
483 if (!i->buf) {
484 if (!(i->buf = malloc(i->fragment_size))) {
485 debug(__FILE__": malloc() failed.\n");
486 return -1;
487 }
488 }
489
490 if ((r = read(i->thread_fd, i->buf, i->fragment_size)) <= 0) {
491
492 if (errno == EAGAIN)
493 break;
494
495 debug(__FILE__": read(): %s\n", r == 0 ? "EOF" : strerror(errno));
496 return -1;
497 }
498
499 if (pa_stream_write(i->stream, i->buf, r, free, 0, PA_SEEK_RELATIVE) < 0) {
500 debug(__FILE__": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i->context)));
501 return -1;
502 }
503
504 i->buf = NULL;
505
506 assert(n >= (size_t) r);
507 n -= r;
508 }
509
510 if (i->io_event) {
511 pa_mainloop_api *api;
512 api = pa_threaded_mainloop_get_api(i->mainloop);
513 api->io_enable(i->io_event, n >= i->fragment_size ? PA_IO_EVENT_INPUT : 0);
514 }
515
516 return 0;
517 }
518
519 static void stream_state_cb(pa_stream *s, void * userdata) {
520 fd_info *i = userdata;
521 assert(s);
522
523 switch (pa_stream_get_state(s)) {
524
525 case PA_STREAM_READY:
526 debug(__FILE__": stream established.\n");
527 break;
528
529 case PA_STREAM_FAILED:
530 debug(__FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
531 fd_info_shutdown(i);
532 break;
533
534 case PA_STREAM_TERMINATED:
535 case PA_STREAM_UNCONNECTED:
536 case PA_STREAM_CREATING:
537 break;
538 }
539 }
540
541 static int create_stream(fd_info *i) {
542 pa_buffer_attr attr;
543 int n;
544
545 assert(i);
546
547 fix_metrics(i);
548
549 if (!(i->stream = pa_stream_new(i->context, "audio stream", &i->sample_spec, NULL))) {
550 debug(__FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
551 goto fail;
552 }
553
554 pa_stream_set_state_callback(i->stream, stream_state_cb, i);
555 pa_stream_set_write_callback(i->stream, stream_request_cb, i);
556 pa_stream_set_latency_update_callback(i->stream, stream_latency_update_cb, i);
557
558 memset(&attr, 0, sizeof(attr));
559 attr.maxlength = i->fragment_size * (i->n_fragments+1);
560 attr.tlength = i->fragment_size * i->n_fragments;
561 attr.prebuf = i->fragment_size;
562 attr.minreq = i->fragment_size;
563
564 if (pa_stream_connect_playback(i->stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) {
565 debug(__FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
566 goto fail;
567 }
568
569 n = i->fragment_size;
570 setsockopt(i->app_fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n));
571 n = i->fragment_size;
572 setsockopt(i->thread_fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));
573
574 return 0;
575
576 fail:
577 return -1;
578 }
579
580 static void free_stream(fd_info *i) {
581 assert(i);
582
583 if (i->stream) {
584 pa_stream_disconnect(i->stream);
585 pa_stream_unref(i->stream);
586 i->stream = NULL;
587 }
588 }
589
590 static void io_event_cb(pa_mainloop_api *api, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) {
591 fd_info *i = userdata;
592
593 pa_threaded_mainloop_signal(i->mainloop, 0);
594
595 if (flags & PA_IO_EVENT_INPUT) {
596
597 if (!i->stream) {
598 api->io_enable(e, 0);
599
600 if (create_stream(i) < 0)
601 goto fail;
602
603 } else {
604 if (fd_info_copy_data(i, 0) < 0)
605 goto fail;
606 }
607
608 } else if (flags & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR))
609 goto fail;
610
611 return;
612
613 fail:
614 /* We can't do anything better than removing the event source */
615 fd_info_shutdown(i);
616 }
617
618 static int dsp_open(int flags, int *_errno) {
619 fd_info *i;
620 pa_mainloop_api *api;
621 int ret;
622 int f;
623
624 if ((flags != O_WRONLY) && (flags != (O_WRONLY|O_NONBLOCK))) {
625 *_errno = EACCES;
626 return -1;
627 }
628
629 if (!(i = fd_info_new(FD_INFO_PLAYBACK, _errno)))
630 return -1;
631
632 shutdown(i->thread_fd, SHUT_WR);
633 shutdown(i->app_fd, SHUT_RD);
634
635 if ((flags & O_NONBLOCK) == O_NONBLOCK) {
636 if ((f = fcntl(i->app_fd, F_GETFL)) >= 0)
637 fcntl(i->app_fd, F_SETFL, f|O_NONBLOCK);
638 }
639 if ((f = fcntl(i->thread_fd, F_GETFL)) >= 0)
640 fcntl(i->thread_fd, F_SETFL, f|O_NONBLOCK);
641
642 fcntl(i->app_fd, F_SETFD, FD_CLOEXEC);
643 fcntl(i->thread_fd, F_SETFD, FD_CLOEXEC);
644
645 pa_threaded_mainloop_lock(i->mainloop);
646 api = pa_threaded_mainloop_get_api(i->mainloop);
647 if (!(i->io_event = api->io_new(api, i->thread_fd, PA_IO_EVENT_INPUT, io_event_cb, i)))
648 goto fail;
649
650 pa_threaded_mainloop_unlock(i->mainloop);
651
652 debug(__FILE__": dsp_open() succeeded, fd=%i\n", i->app_fd);
653
654 fd_info_add_to_list(i);
655 ret = i->app_fd;
656 fd_info_unref(i);
657
658 return ret;
659
660 fail:
661 pa_threaded_mainloop_unlock(i->mainloop);
662
663 if (i)
664 fd_info_unref(i);
665
666 *_errno = EIO;
667
668 debug(__FILE__": dsp_open() failed\n");
669
670 return -1;
671 }
672
673 static int mixer_open(int flags, int *_errno) {
674 /* fd_info *i; */
675
676 *_errno = ENOSYS;
677 return -1;
678
679 /* if (!(i = fd_info_new(FD_INFO_MIXER))) */
680 /* return -1; */
681
682 }
683
684 int open(const char *filename, int flags, ...) {
685 va_list args;
686 mode_t mode = 0;
687 int r, _errno = 0;
688
689 va_start(args, flags);
690 if (flags & O_CREAT)
691 mode = va_arg(args, mode_t);
692 va_end(args);
693
694 if (!function_enter()) {
695 LOAD_OPEN_FUNC();
696 return _open(filename, flags, mode);
697 }
698
699 debug(__FILE__": open()\n");
700
701 if (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0) {
702 r = dsp_open(flags, &_errno);
703 } else if (strcmp(filename, "/dev/mixer") == 0) {
704 r = mixer_open(flags, &_errno);
705 } else {
706 function_exit();
707 LOAD_OPEN_FUNC();
708 return _open(filename, flags, mode);
709 }
710
711 function_exit();
712
713 if (_errno)
714 errno = _errno;
715
716 return r;
717 }
718
719 static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) {
720 *_errno = ENOSYS;
721 return -1;
722 }
723
724 static int map_format(int *fmt, pa_sample_spec *ss) {
725
726 switch (*fmt) {
727 case AFMT_MU_LAW:
728 ss->format = PA_SAMPLE_ULAW;
729 break;
730
731 case AFMT_A_LAW:
732 ss->format = PA_SAMPLE_ALAW;
733 break;
734
735 case AFMT_S8:
736 *fmt = AFMT_U8;
737 /* fall through */
738 case AFMT_U8:
739 ss->format = PA_SAMPLE_U8;
740 break;
741
742 case AFMT_U16_BE:
743 *fmt = AFMT_S16_BE;
744 /* fall through */
745 case AFMT_S16_BE:
746 ss->format = PA_SAMPLE_S16BE;
747 break;
748
749 case AFMT_U16_LE:
750 *fmt = AFMT_S16_LE;
751 /* fall through */
752 case AFMT_S16_LE:
753 ss->format = PA_SAMPLE_S16LE;
754 break;
755
756 default:
757 ss->format = PA_SAMPLE_S16NE;
758 *fmt = AFMT_S16_NE;
759 break;
760 }
761
762 return 0;
763 }
764
765 static int map_format_back(pa_sample_format_t format) {
766 switch (format) {
767 case PA_SAMPLE_S16LE: return AFMT_S16_LE;
768 case PA_SAMPLE_S16BE: return AFMT_S16_BE;
769 case PA_SAMPLE_ULAW: return AFMT_MU_LAW;
770 case PA_SAMPLE_ALAW: return AFMT_A_LAW;
771 case PA_SAMPLE_U8: return AFMT_U8;
772 default:
773 abort();
774 }
775 }
776
777 static void success_cb(pa_stream *s, int success, void *userdata) {
778 fd_info *i = userdata;
779
780 assert(s);
781 assert(i);
782
783 i->operation_success = success;
784 pa_threaded_mainloop_signal(i->mainloop, 0);
785 }
786
787 static int dsp_empty_socket(fd_info *i) {
788 int ret = -1;
789
790 /* Empty the socket */
791 for (;;) {
792 int l;
793
794 if (i->thread_fd < 0)
795 break;
796
797 if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) {
798 debug(__FILE__": SIOCINQ: %s\n", strerror(errno));
799 break;
800 }
801
802 if (!l)
803 break;
804
805 pa_threaded_mainloop_wait(i->mainloop);
806 }
807
808 return ret;
809 }
810
811 static int dsp_drain(fd_info *i) {
812 pa_operation *o = NULL;
813 int r = -1;
814
815 if (!i->mainloop)
816 return 0;
817
818 debug(__FILE__": Draining.\n");
819
820 pa_threaded_mainloop_lock(i->mainloop);
821
822 if (dsp_empty_socket(i) < 0)
823 goto fail;
824
825 if (!i->stream)
826 goto fail;
827
828 debug(__FILE__": Really draining.\n");
829
830 if (!(o = pa_stream_drain(i->stream, success_cb, i))) {
831 debug(__FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context)));
832 goto fail;
833 }
834
835 i->operation_success = 0;
836 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
837 if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY)
838 goto fail;
839
840 pa_threaded_mainloop_wait(i->mainloop);
841 }
842
843 if (!i->operation_success) {
844 debug(__FILE__": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i->context)));
845 goto fail;
846 }
847
848 r = 0;
849
850 fail:
851
852 if (o)
853 pa_operation_unref(o);
854
855 pa_threaded_mainloop_unlock(i->mainloop);
856
857 return 0;
858 }
859
860 static int dsp_trigger(fd_info *i) {
861 pa_operation *o = NULL;
862 int r = -1;
863
864 fd_info_copy_data(i, 1);
865
866 if (!i->stream)
867 return 0;
868
869 pa_threaded_mainloop_lock(i->mainloop);
870
871 if (dsp_empty_socket(i) < 0)
872 goto fail;
873
874 debug(__FILE__": Triggering.\n");
875
876 if (!(o = pa_stream_trigger(i->stream, success_cb, i))) {
877 debug(__FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context)));
878 goto fail;
879 }
880
881 i->operation_success = 0;
882 while (!pa_operation_get_state(o) != PA_OPERATION_DONE) {
883 if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY)
884 goto fail;
885
886 pa_threaded_mainloop_wait(i->mainloop);
887 }
888
889 if (!i->operation_success) {
890 debug(__FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context)));
891 goto fail;
892 }
893
894 r = 0;
895
896 fail:
897
898 if (o)
899 pa_operation_unref(o);
900
901 pa_threaded_mainloop_unlock(i->mainloop);
902
903 return 0;
904 }
905
906 static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) {
907 int ret = -1;
908
909 switch (request) {
910 case SNDCTL_DSP_SETFMT: {
911 debug(__FILE__": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp);
912
913 pa_threaded_mainloop_lock(i->mainloop);
914
915 if (*(int*) argp == AFMT_QUERY)
916 *(int*) argp = map_format_back(i->sample_spec.format);
917 else {
918 map_format((int*) argp, &i->sample_spec);
919 free_stream(i);
920 }
921
922 pa_threaded_mainloop_unlock(i->mainloop);
923 break;
924 }
925
926 case SNDCTL_DSP_SPEED: {
927 pa_sample_spec ss;
928 int valid;
929
930 debug(__FILE__": SNDCTL_DSP_SPEED: %i\n", *(int*) argp);
931
932 pa_threaded_mainloop_lock(i->mainloop);
933
934 ss = i->sample_spec;
935 ss.rate = *(int*) argp;
936
937 if ((valid = pa_sample_spec_valid(&ss))) {
938 i->sample_spec = ss;
939 free_stream(i);
940 }
941
942 pa_threaded_mainloop_unlock(i->mainloop);
943
944 if (!valid) {
945 *_errno = EINVAL;
946 goto fail;
947 }
948
949 break;
950 }
951
952 case SNDCTL_DSP_STEREO:
953 debug(__FILE__": SNDCTL_DSP_STEREO: %i\n", *(int*) argp);
954
955 pa_threaded_mainloop_lock(i->mainloop);
956
957 i->sample_spec.channels = *(int*) argp ? 2 : 1;
958 free_stream(i);
959
960 pa_threaded_mainloop_unlock(i->mainloop);
961 return 0;
962
963 case SNDCTL_DSP_CHANNELS: {
964 pa_sample_spec ss;
965 int valid;
966
967 debug(__FILE__": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp);
968
969 pa_threaded_mainloop_lock(i->mainloop);
970
971 ss = i->sample_spec;
972 ss.channels = *(int*) argp;
973
974 if ((valid = pa_sample_spec_valid(&ss))) {
975 i->sample_spec = ss;
976 free_stream(i);
977 }
978
979 pa_threaded_mainloop_unlock(i->mainloop);
980
981 if (!valid) {
982 *_errno = EINVAL;
983 goto fail;
984 }
985
986 break;
987 }
988
989 case SNDCTL_DSP_GETBLKSIZE:
990 debug(__FILE__": SNDCTL_DSP_GETBLKSIZE\n");
991
992 pa_threaded_mainloop_lock(i->mainloop);
993
994 fix_metrics(i);
995 *(int*) argp = i->fragment_size;
996
997 pa_threaded_mainloop_unlock(i->mainloop);
998
999 break;
1000
1001 case SNDCTL_DSP_SETFRAGMENT:
1002 debug(__FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%8x\n", *(int*) argp);
1003
1004 pa_threaded_mainloop_lock(i->mainloop);
1005
1006 i->fragment_size = 1 << (*(int*) argp);
1007 i->n_fragments = (*(int*) argp) >> 16;
1008
1009 free_stream(i);
1010
1011 pa_threaded_mainloop_unlock(i->mainloop);
1012
1013 break;
1014
1015 case SNDCTL_DSP_GETCAPS:
1016 debug(__FILE__": SNDCTL_DSP_CAPS\n");
1017
1018 *(int*) argp = DSP_CAP_MULTI;
1019 break;
1020
1021 case SNDCTL_DSP_GETODELAY: {
1022 int l;
1023
1024 debug(__FILE__": SNDCTL_DSP_GETODELAY\n");
1025
1026 pa_threaded_mainloop_lock(i->mainloop);
1027
1028 *(int*) argp = 0;
1029
1030 for (;;) {
1031 pa_usec_t usec;
1032 if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY)
1033 break;
1034
1035 if (pa_stream_get_latency(i->stream, &usec, NULL) >= 0) {
1036 *(int*) argp = pa_usec_to_bytes(usec, &i->sample_spec);
1037 break;
1038 }
1039
1040 if (pa_context_errno(i->context) != PA_ERR_NODATA) {
1041 debug(__FILE__": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i->context)));
1042 break;
1043 }
1044
1045 pa_threaded_mainloop_wait(i->mainloop);
1046 }
1047
1048 if (ioctl(i->thread_fd, SIOCINQ, &l) < 0)
1049 debug(__FILE__": SIOCINQ failed: %s\n", strerror(errno));
1050 else
1051 *(int*) argp += l;
1052
1053 pa_threaded_mainloop_unlock(i->mainloop);
1054
1055 debug(__FILE__": ODELAY: %i\n", *(int*) argp);
1056
1057 break;
1058 }
1059
1060 case SNDCTL_DSP_RESET: {
1061 debug(__FILE__": SNDCTL_DSP_RESET\n");
1062
1063 pa_threaded_mainloop_lock(i->mainloop);
1064
1065 free_stream(i);
1066 reset_params(i);
1067
1068 pa_threaded_mainloop_unlock(i->mainloop);
1069 break;
1070 }
1071
1072 case SNDCTL_DSP_GETFMTS: {
1073 debug(__FILE__": SNDCTL_DSP_GETFMTS\n");
1074
1075 *(int*) argp = AFMT_MU_LAW|AFMT_A_LAW|AFMT_U8|AFMT_S16_LE|AFMT_S16_BE;
1076 break;
1077 }
1078
1079 case SNDCTL_DSP_POST:
1080 debug(__FILE__": SNDCTL_DSP_POST\n");
1081
1082 if (dsp_trigger(i) < 0)
1083 *_errno = EIO;
1084 break;
1085
1086 case SNDCTL_DSP_SYNC:
1087 debug(__FILE__": SNDCTL_DSP_SYNC\n");
1088
1089 if (dsp_drain(i) < 0)
1090 *_errno = EIO;
1091
1092 break;
1093
1094 case SNDCTL_DSP_GETOSPACE: {
1095 audio_buf_info *bi = (audio_buf_info*) argp;
1096 int l;
1097 size_t k = 0;
1098
1099 debug(__FILE__": SNDCTL_DSP_GETOSPACE\n");
1100
1101 pa_threaded_mainloop_lock(i->mainloop);
1102
1103 fix_metrics(i);
1104
1105 if (i->stream) {
1106 if ((k = pa_stream_writable_size(i->stream)) == (size_t) -1)
1107 debug(__FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context)));
1108 } else
1109 k = i->fragment_size * i->n_fragments;
1110
1111 if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) {
1112 debug(__FILE__": SIOCINQ failed: %s\n", strerror(errno));
1113 l = 0;
1114 }
1115
1116 bi->fragsize = i->fragment_size;
1117 bi->fragstotal = i->n_fragments;
1118 bi->bytes = k > (size_t) l ? k - l : 0;
1119 bi->fragments = bi->bytes / bi->fragsize;
1120
1121 pa_threaded_mainloop_unlock(i->mainloop);
1122
1123 debug(__FILE__": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi->fragsize, bi->fragstotal, bi->bytes, bi->fragments);
1124
1125 break;
1126 }
1127
1128 default:
1129 debug(__FILE__": unknwon ioctl 0x%08lx\n", request);
1130
1131 *_errno = EINVAL;
1132 goto fail;
1133 }
1134
1135 ret = 0;
1136
1137 fail:
1138
1139 return ret;
1140 }
1141
1142 int ioctl(int fd, unsigned long request, ...) {
1143 fd_info *i;
1144 va_list args;
1145 void *argp;
1146 int r, _errno = 0;
1147
1148 debug(__FILE__": ioctl()\n");
1149
1150 va_start(args, request);
1151 argp = va_arg(args, void *);
1152 va_end(args);
1153
1154 if (!function_enter()) {
1155 LOAD_IOCTL_FUNC();
1156 return _ioctl(fd, request, argp);
1157 }
1158
1159 if (!(i = fd_info_find(fd))) {
1160 function_exit();
1161 LOAD_IOCTL_FUNC();
1162 return _ioctl(fd, request, argp);
1163 }
1164
1165 if (i->type == FD_INFO_MIXER)
1166 r = mixer_ioctl(i, request, argp, &_errno);
1167 else
1168 r = dsp_ioctl(i, request, argp, &_errno);
1169
1170 fd_info_unref(i);
1171
1172 if (_errno)
1173 errno = _errno;
1174
1175 function_exit();
1176
1177 return r;
1178 }
1179
1180 int close(int fd) {
1181 fd_info *i;
1182
1183 debug(__FILE__": close()\n");
1184
1185 if (!function_enter()) {
1186 LOAD_CLOSE_FUNC();
1187 return _close(fd);
1188 }
1189
1190 if (!(i = fd_info_find(fd))) {
1191 function_exit();
1192 LOAD_CLOSE_FUNC();
1193 return _close(fd);
1194 }
1195
1196 fd_info_remove_from_list(i);
1197 fd_info_unref(i);
1198
1199 function_exit();
1200
1201 return 0;
1202 }
1203
1204 int open64(const char *filename, int flags, ...) {
1205 va_list args;
1206 mode_t mode = 0;
1207
1208 debug(__FILE__": open64()\n");
1209
1210 va_start(args, flags);
1211 if (flags & O_CREAT)
1212 mode = va_arg(args, mode_t);
1213 va_end(args);
1214
1215 if (strcmp(filename, "/dev/dsp") != 0 &&
1216 strcmp(filename, "/dev/adsp") != 0 &&
1217 strcmp(filename, "/dev/mixer") != 0) {
1218 LOAD_OPEN64_FUNC();
1219 return _open64(filename, flags, mode);
1220 }
1221
1222 return open(filename, flags, mode);
1223 }
1224
1225 FILE* fopen(const char *filename, const char *mode) {
1226 FILE *f = NULL;
1227 int fd;
1228
1229 debug(__FILE__": fopen()\n");
1230
1231 if (strcmp(filename, "/dev/dsp") != 0 &&
1232 strcmp(filename, "/dev/adsp") != 0 &&
1233 strcmp(filename, "/dev/mixer") != 0) {
1234 LOAD_FOPEN_FUNC();
1235 return _fopen(filename, mode);
1236 }
1237
1238 if (strcmp(mode, "wb") != 0) {
1239 errno = EACCES;
1240 return NULL;
1241 }
1242
1243 if ((fd = open(filename, O_WRONLY)) < 0)
1244 return NULL;
1245
1246 if (!(f = fdopen(fd, "wb"))) {
1247 close(fd);
1248 return NULL;
1249 }
1250
1251 return f;
1252 }
1253
1254 FILE *fopen64(const char *filename, const char *mode) {
1255
1256 debug(__FILE__": fopen64()\n");
1257
1258 if (strcmp(filename, "/dev/dsp") != 0 &&
1259 strcmp(filename, "/dev/adsp") != 0 &&
1260 strcmp(filename, "/dev/mixer") != 0) {
1261 LOAD_FOPEN64_FUNC();
1262 return _fopen64(filename, mode);
1263 }
1264
1265 return fopen(filename, mode);
1266 }
1267
1268 int fclose(FILE *f) {
1269 fd_info *i;
1270
1271 debug(__FILE__": fclose()\n");
1272
1273 if (!function_enter()) {
1274 LOAD_FCLOSE_FUNC();
1275 return _fclose(f);
1276 }
1277
1278 if (!(i = fd_info_find(fileno(f)))) {
1279 function_exit();
1280 LOAD_FCLOSE_FUNC();
1281 return _fclose(f);
1282 }
1283
1284 fd_info_remove_from_list(i);
1285
1286 /* Dirty trick to avoid that the fd is not freed twice, once by us
1287 * and once by the real fclose() */
1288 i->app_fd = -1;
1289
1290 fd_info_unref(i);
1291
1292 function_exit();
1293
1294 LOAD_FCLOSE_FUNC();
1295 return _fclose(f);
1296 }