From 103154940d09855b102ab823f032e854f5327ba1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 May 2006 14:42:23 +0000 Subject: add new padsp utility: a $LD_PRELOAD wrapper for using the OSS API with polypaudio git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@950 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 1284 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1284 insertions(+) create mode 100644 src/utils/padsp.c (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c new file mode 100644 index 00000000..06bdd575 --- /dev/null +++ b/src/utils/padsp.c @@ -0,0 +1,1284 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef _FILE_OFFSET_BITS +#undef _FILE_OFFSET_BITS +#endif + +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE 1 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +typedef enum { + FD_INFO_MIXER, + FD_INFO_PLAYBACK +} fd_info_type_t; + +typedef struct fd_info fd_info; + +struct fd_info { + pthread_mutex_t mutex; + int ref; + + fd_info_type_t type; + int app_fd, thread_fd; + + pa_sample_spec sample_spec; + size_t fragment_size; + unsigned n_fragments; + + pa_threaded_mainloop *mainloop; + pa_context *context; + pa_stream *stream; + + pa_io_event *io_event; + + void *buf; + + int operation_success; + + PA_LLIST_FIELDS(fd_info); +}; + +static int dsp_drain(fd_info *i); + +static pthread_mutex_t fd_infos_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t func_mutex = PTHREAD_MUTEX_INITIALIZER; + +static PA_LLIST_HEAD(fd_info, fd_infos) = NULL; + +static int (*_ioctl)(int, int, void*) = NULL; +static int (*_close)(int) = NULL; +static int (*_open)(const char *, int, mode_t) = NULL; +static FILE* (*_fopen)(const char *path, const char *mode) = NULL; +static int (*_open64)(const char *, int, mode_t) = NULL; +static FILE* (*_fopen64)(const char *path, const char *mode) = NULL; +static int (*_fclose)(FILE *f) = NULL; + +#define LOAD_IOCTL_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_ioctl) \ + _ioctl = (int (*)(int, int, void*)) dlsym(RTLD_NEXT, "ioctl"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_OPEN_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_open) \ + _open = (int (*)(const char *, int, mode_t)) dlsym(RTLD_NEXT, "open"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_OPEN64_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_open64) \ + _open64 = (int (*)(const char *, int, mode_t)) dlsym(RTLD_NEXT, "open64"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_CLOSE_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_close) \ + _close = (int (*)(int)) dlsym(RTLD_NEXT, "close"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_FOPEN_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_fopen) \ + _fopen = (FILE* (*)(const char *, const char*)) dlsym(RTLD_NEXT, "fopen"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_FOPEN64_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_fopen64) \ + _fopen64 = (FILE* (*)(const char *, const char*)) dlsym(RTLD_NEXT, "fopen64"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_FCLOSE_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_fclose) \ + _fclose = (int (*)(FILE *)) dlsym(RTLD_NEXT, "fclose"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +static void debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); + +static void debug(const char *format, ...) { + va_list ap; + if (getenv("PADSP_DEBUG")) { + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + } +} + +static pthread_key_t recursion_key; + +static void recursion_key_alloc(void) { + pthread_key_create(&recursion_key, NULL); +} + +static int function_enter(void) { + /* Avoid recursive calls */ + static pthread_once_t recursion_key_once = PTHREAD_ONCE_INIT; + pthread_once(&recursion_key_once, recursion_key_alloc); + + if (pthread_getspecific(recursion_key)) + return 0; + + pthread_setspecific(recursion_key, (void*) 1); + return 1; +} + +static void function_exit(void) { + pthread_setspecific(recursion_key, NULL); +} + +static void fd_info_free(fd_info *i) { + assert(i); + + debug(__FILE__": freeing fd info (fd=%i)\n", i->app_fd); + + dsp_drain(i); + + if (i->mainloop) + pa_threaded_mainloop_stop(i->mainloop); + + if (i->stream) { + pa_stream_disconnect(i->stream); + pa_stream_unref(i->stream); + } + + if (i->context) { + pa_context_disconnect(i->context); + pa_context_unref(i->context); + } + + if (i->mainloop) + pa_threaded_mainloop_free(i->mainloop); + + if (i->app_fd >= 0) { + LOAD_CLOSE_FUNC(); + _close(i->app_fd); + } + + if (i->thread_fd >= 0) { + LOAD_CLOSE_FUNC(); + _close(i->thread_fd); + } + + free(i->buf); + + pthread_mutex_destroy(&i->mutex); + free(i); +} + +static fd_info *fd_info_ref(fd_info *i) { + assert(i); + + pthread_mutex_lock(&i->mutex); + assert(i->ref >= 1); + i->ref++; + +/* debug(__FILE__": ref++, now %i\n", i->ref); */ + pthread_mutex_unlock(&i->mutex); + + return i; +} + +static void fd_info_unref(fd_info *i) { + int r; + pthread_mutex_lock(&i->mutex); + assert(i->ref >= 1); + r = --i->ref; +/* debug(__FILE__": ref--, now %i\n", i->ref); */ + pthread_mutex_unlock(&i->mutex); + + if (r <= 0) + fd_info_free(i); +} + +static void context_state_cb(pa_context *c, void *userdata) { + fd_info *i = userdata; + assert(c); + + switch (pa_context_get_state(c)) { + case PA_CONTEXT_READY: + case PA_CONTEXT_TERMINATED: + case PA_CONTEXT_FAILED: + pa_threaded_mainloop_signal(i->mainloop, 0); + break; + + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + } +} + +static void reset_params(fd_info *i) { + assert(i); + + i->sample_spec.format = PA_SAMPLE_ULAW; + i->sample_spec.channels = 1; + i->sample_spec.rate = 8000; + i->fragment_size = 1024; + i->n_fragments = 0; +} + +static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { + fd_info *i; + int sfds[2] = { -1, -1 }; + + debug(__FILE__": fd_info_new()\n"); + + signal(SIGPIPE, SIG_IGN); /* Yes, ugly as hell */ + + if (!(i = malloc(sizeof(fd_info)))) { + *_errno = ENOMEM; + goto fail; + } + + i->app_fd = i->thread_fd = -1; + i->type = type; + + i->mainloop = NULL; + i->context = NULL; + i->stream = NULL; + i->io_event = NULL; + pthread_mutex_init(&i->mutex, NULL); + i->ref = 1; + i->buf = NULL; + PA_LLIST_INIT(fd_info, i); + + reset_params(i); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfds) < 0) { + *_errno = errno; + debug(__FILE__": socket() failed: %s\n", strerror(errno)); + goto fail; + } + + i->app_fd = sfds[0]; + i->thread_fd = sfds[1]; + + if (!(i->mainloop = pa_threaded_mainloop_new())) { + *_errno = EIO; + debug(__FILE__": pa_threaded_mainloop_new() failed\n"); + goto fail; + } + + if (!(i->context = pa_context_new(pa_threaded_mainloop_get_api(i->mainloop), "oss"))) { + *_errno = EIO; + debug(__FILE__": pa_context_new() failed\n"); + goto fail; + } + + pa_context_set_state_callback(i->context, context_state_cb, i); + + if (pa_context_connect(i->context, NULL, 0, NULL) < 0) { + *_errno = ECONNREFUSED; + debug(__FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + pa_threaded_mainloop_lock(i->mainloop); + + if (pa_threaded_mainloop_start(i->mainloop) < 0) { + *_errno = EIO; + debug(__FILE__": pa_threaded_mainloop_start() failed\n"); + goto unlock_and_fail; + } + + /* Wait until the context is ready */ + pa_threaded_mainloop_wait(i->mainloop); + + if (pa_context_get_state(i->context) != PA_CONTEXT_READY) { + *_errno = ECONNREFUSED; + debug(__FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + goto unlock_and_fail; + } + + pa_threaded_mainloop_unlock(i->mainloop); + return i; + +unlock_and_fail: + + pa_threaded_mainloop_unlock(i->mainloop); + +fail: + + if (i) + fd_info_unref(i); + + return NULL; +} + +static void fd_info_add_to_list(fd_info *i) { + assert(i); + + pthread_mutex_lock(&fd_infos_mutex); + PA_LLIST_PREPEND(fd_info, fd_infos, i); + pthread_mutex_unlock(&fd_infos_mutex); + + fd_info_ref(i); +} + +static void fd_info_remove_from_list(fd_info *i) { + assert(i); + + pthread_mutex_lock(&fd_infos_mutex); + PA_LLIST_REMOVE(fd_info, fd_infos, i); + pthread_mutex_unlock(&fd_infos_mutex); + + fd_info_unref(i); +} + +static fd_info* fd_info_find(int fd) { + fd_info *i; + + pthread_mutex_lock(&fd_infos_mutex); + + for (i = fd_infos; i; i = i->next) + if (i->app_fd == fd) { + fd_info_ref(i); + break; + } + + pthread_mutex_unlock(&fd_infos_mutex); + + return i; +} + +static void fix_metrics(fd_info *i) { + size_t fs; + char t[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + fs = pa_frame_size(&i->sample_spec); + i->fragment_size = (i->fragment_size/fs)*fs; + + if (i->n_fragments < 2) + i->n_fragments = 12; + + if (i->fragment_size <= 0) + if ((i->fragment_size = pa_bytes_per_second(&i->sample_spec) / 2 / i->n_fragments) <= 0) + i->fragment_size = 1024; + + debug(__FILE__": sample spec: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); + debug(__FILE__": fixated metrics to %i fragments, %i bytes each.\n", i->n_fragments, i->fragment_size); +} + +static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { + fd_info *i = userdata; + assert(s); + + if (i->io_event) { + pa_mainloop_api *api; + api = pa_threaded_mainloop_get_api(i->mainloop); + api->io_enable(i->io_event, PA_IO_EVENT_INPUT); + } +} + +static void stream_latency_update_cb(pa_stream *s, void *userdata) { + fd_info *i = userdata; + assert(s); + + pa_threaded_mainloop_signal(i->mainloop, 0); +} + +static void fd_info_shutdown(fd_info *i) { + assert(i); + + if (i->io_event) { + pa_mainloop_api *api; + api = pa_threaded_mainloop_get_api(i->mainloop); + api->io_free(i->io_event); + i->io_event = NULL; + } + + if (i->thread_fd >= 0) { + close(i->thread_fd); + i->thread_fd = -1; + } +} + +static int fd_info_copy_data(fd_info *i, int force) { + size_t n; + + if (!i->stream) + return -1; + + if ((n = pa_stream_writable_size(i->stream)) == (size_t) -1) { + debug(__FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); + return -1; + } + + while (n >= i->fragment_size || force) { + ssize_t r; + + if (!i->buf) { + if (!(i->buf = malloc(i->fragment_size))) { + debug(__FILE__": malloc() failed.\n"); + return -1; + } + } + + if ((r = read(i->thread_fd, i->buf, i->fragment_size)) <= 0) { + + if (errno == EAGAIN) + break; + + debug(__FILE__": read(): %s\n", r == 0 ? "EOF" : strerror(errno)); + return -1; + } + + if (pa_stream_write(i->stream, i->buf, r, free, 0, PA_SEEK_RELATIVE) < 0) { + debug(__FILE__": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i->context))); + return -1; + } + + i->buf = NULL; + + assert(n >= (size_t) r); + n -= r; + } + + if (i->io_event) { + pa_mainloop_api *api; + api = pa_threaded_mainloop_get_api(i->mainloop); + api->io_enable(i->io_event, n >= i->fragment_size ? PA_IO_EVENT_INPUT : 0); + } + + return 0; +} + +static void stream_state_cb(pa_stream *s, void * userdata) { + fd_info *i = userdata; + assert(s); + + switch (pa_stream_get_state(s)) { + + case PA_STREAM_READY: + debug(__FILE__": stream established.\n"); + break; + + case PA_STREAM_FAILED: + debug(__FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + fd_info_shutdown(i); + break; + + case PA_STREAM_TERMINATED: + case PA_STREAM_UNCONNECTED: + case PA_STREAM_CREATING: + break; + } +} + +static int create_stream(fd_info *i) { + pa_buffer_attr attr; + int n; + + assert(i); + + fix_metrics(i); + + if (!(i->stream = pa_stream_new(i->context, "audio stream", &i->sample_spec, NULL))) { + debug(__FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + pa_stream_set_state_callback(i->stream, stream_state_cb, i); + pa_stream_set_write_callback(i->stream, stream_request_cb, i); + pa_stream_set_latency_update_callback(i->stream, stream_latency_update_cb, i); + + memset(&attr, 0, sizeof(attr)); + attr.maxlength = i->fragment_size * (i->n_fragments+1); + attr.tlength = i->fragment_size * i->n_fragments; + attr.prebuf = i->fragment_size; + attr.minreq = i->fragment_size; + + if (pa_stream_connect_playback(i->stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) { + debug(__FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + n = i->fragment_size; + setsockopt(i->app_fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)); + n = i->fragment_size; + setsockopt(i->thread_fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)); + + return 0; + +fail: + return -1; +} + +static void free_stream(fd_info *i) { + assert(i); + + if (i->stream) { + pa_stream_disconnect(i->stream); + pa_stream_unref(i->stream); + i->stream = NULL; + } +} + +static void io_event_cb(pa_mainloop_api *api, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) { + fd_info *i = userdata; + + pa_threaded_mainloop_signal(i->mainloop, 0); + + if (flags & PA_IO_EVENT_INPUT) { + + if (!i->stream) { + api->io_enable(e, 0); + + if (create_stream(i) < 0) + goto fail; + + } else { + if (fd_info_copy_data(i, 0) < 0) + goto fail; + } + + } else if (flags & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) + goto fail; + + return; + +fail: + /* We can't do anything better than removing the event source */ + fd_info_shutdown(i); +} + +static int dsp_open(int flags, int *_errno) { + fd_info *i; + pa_mainloop_api *api; + int ret; + int f; + + if ((flags != O_WRONLY) && (flags != (O_WRONLY|O_NONBLOCK))) { + *_errno = EACCES; + return -1; + } + + if (!(i = fd_info_new(FD_INFO_PLAYBACK, _errno))) + return -1; + + shutdown(i->thread_fd, SHUT_WR); + shutdown(i->app_fd, SHUT_RD); + + if ((flags & O_NONBLOCK) == O_NONBLOCK) { + if ((f = fcntl(i->app_fd, F_GETFL)) >= 0) + fcntl(i->app_fd, F_SETFL, f|O_NONBLOCK); + } + if ((f = fcntl(i->thread_fd, F_GETFL)) >= 0) + fcntl(i->thread_fd, F_SETFL, f|O_NONBLOCK); + + fcntl(i->app_fd, F_SETFD, FD_CLOEXEC); + fcntl(i->thread_fd, F_SETFD, FD_CLOEXEC); + + pa_threaded_mainloop_lock(i->mainloop); + api = pa_threaded_mainloop_get_api(i->mainloop); + if (!(i->io_event = api->io_new(api, i->thread_fd, PA_IO_EVENT_INPUT, io_event_cb, i))) + goto fail; + + pa_threaded_mainloop_unlock(i->mainloop); + + debug(__FILE__": dsp_open() succeeded, fd=%i\n", i->app_fd); + + fd_info_add_to_list(i); + ret = i->app_fd; + fd_info_unref(i); + + return ret; + +fail: + pa_threaded_mainloop_unlock(i->mainloop); + + if (i) + fd_info_unref(i); + + *_errno = EIO; + + debug(__FILE__": dsp_open() failed\n"); + + return -1; +} + +static int mixer_open(int flags, int *_errno) { +/* fd_info *i; */ + + *_errno = ENOSYS; + return -1; + +/* if (!(i = fd_info_new(FD_INFO_MIXER))) */ +/* return -1; */ + +} + +int open(const char *filename, int flags, ...) { + va_list args; + mode_t mode = 0; + int r, _errno = 0; + + va_start(args, flags); + if (flags & O_CREAT) + mode = va_arg(args, mode_t); + va_end(args); + + if (!function_enter()) { + LOAD_OPEN_FUNC(); + return _open(filename, flags, mode); + } + + debug(__FILE__": open()\n"); + + if (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0) { + r = dsp_open(flags, &_errno); + } else if (strcmp(filename, "/dev/mixer") == 0) { + r = mixer_open(flags, &_errno); + } else { + function_exit(); + LOAD_OPEN_FUNC(); + return _open(filename, flags, mode); + } + + function_exit(); + + if (_errno) + errno = _errno; + + return r; +} + +static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { + *_errno = ENOSYS; + return -1; +} + +static int map_format(int *fmt, pa_sample_spec *ss) { + + switch (*fmt) { + case AFMT_MU_LAW: + ss->format = PA_SAMPLE_ULAW; + break; + + case AFMT_A_LAW: + ss->format = PA_SAMPLE_ALAW; + break; + + case AFMT_S8: + *fmt = AFMT_U8; + /* fall through */ + case AFMT_U8: + ss->format = PA_SAMPLE_U8; + break; + + case AFMT_U16_BE: + *fmt = AFMT_S16_BE; + /* fall through */ + case AFMT_S16_BE: + ss->format = PA_SAMPLE_S16BE; + break; + + case AFMT_U16_LE: + *fmt = AFMT_S16_LE; + /* fall through */ + case AFMT_S16_LE: + ss->format = PA_SAMPLE_S16LE; + break; + + default: + ss->format = PA_SAMPLE_S16NE; + *fmt = AFMT_S16_NE; + break; + } + + return 0; +} + +static int map_format_back(pa_sample_format_t format) { + switch (format) { + case PA_SAMPLE_S16LE: return AFMT_S16_LE; + case PA_SAMPLE_S16BE: return AFMT_S16_BE; + case PA_SAMPLE_ULAW: return AFMT_MU_LAW; + case PA_SAMPLE_ALAW: return AFMT_A_LAW; + case PA_SAMPLE_U8: return AFMT_U8; + default: + abort(); + } +} + +static void success_cb(pa_stream *s, int success, void *userdata) { + fd_info *i = userdata; + + assert(s); + assert(i); + + i->operation_success = success; + pa_threaded_mainloop_signal(i->mainloop, 0); +} + +static int dsp_empty_socket(fd_info *i) { + int ret = -1; + + /* Empty the socket */ + for (;;) { + int l; + + if (i->thread_fd < 0) + break; + + if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { + debug(__FILE__": SIOCINQ: %s\n", strerror(errno)); + break; + } + + if (!l) + break; + + pa_threaded_mainloop_wait(i->mainloop); + } + + return ret; +} + +static int dsp_drain(fd_info *i) { + pa_operation *o = NULL; + int r = -1; + + if (!i->mainloop) + return 0; + + debug(__FILE__": Draining.\n"); + + pa_threaded_mainloop_lock(i->mainloop); + + if (dsp_empty_socket(i) < 0) + goto fail; + + if (!i->stream) + goto fail; + + debug(__FILE__": Really draining.\n"); + + if (!(o = pa_stream_drain(i->stream, success_cb, i))) { + debug(__FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + i->operation_success = 0; + while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY) + goto fail; + + pa_threaded_mainloop_wait(i->mainloop); + } + + if (!i->operation_success) { + debug(__FILE__": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + r = 0; + +fail: + + if (o) + pa_operation_unref(o); + + pa_threaded_mainloop_unlock(i->mainloop); + + return 0; +} + +static int dsp_trigger(fd_info *i) { + pa_operation *o = NULL; + int r = -1; + + fd_info_copy_data(i, 1); + + if (!i->stream) + return 0; + + pa_threaded_mainloop_lock(i->mainloop); + + if (dsp_empty_socket(i) < 0) + goto fail; + + debug(__FILE__": Triggering.\n"); + + if (!(o = pa_stream_trigger(i->stream, success_cb, i))) { + debug(__FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + i->operation_success = 0; + while (!pa_operation_get_state(o) != PA_OPERATION_DONE) { + if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY) + goto fail; + + pa_threaded_mainloop_wait(i->mainloop); + } + + if (!i->operation_success) { + debug(__FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + r = 0; + +fail: + + if (o) + pa_operation_unref(o); + + pa_threaded_mainloop_unlock(i->mainloop); + + return 0; +} + +static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { + int ret = -1; + + switch (request) { + case SNDCTL_DSP_SETFMT: { + debug(__FILE__": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp); + + pa_threaded_mainloop_lock(i->mainloop); + + if (*(int*) argp == AFMT_QUERY) + *(int*) argp = map_format_back(i->sample_spec.format); + else { + map_format((int*) argp, &i->sample_spec); + free_stream(i); + } + + pa_threaded_mainloop_unlock(i->mainloop); + break; + } + + case SNDCTL_DSP_SPEED: { + pa_sample_spec ss; + int valid; + + debug(__FILE__": SNDCTL_DSP_SPEED: %i\n", *(int*) argp); + + pa_threaded_mainloop_lock(i->mainloop); + + ss = i->sample_spec; + ss.rate = *(int*) argp; + + if ((valid = pa_sample_spec_valid(&ss))) { + i->sample_spec = ss; + free_stream(i); + } + + pa_threaded_mainloop_unlock(i->mainloop); + + if (!valid) { + *_errno = EINVAL; + goto fail; + } + + break; + } + + case SNDCTL_DSP_STEREO: + debug(__FILE__": SNDCTL_DSP_STEREO: %i\n", *(int*) argp); + + pa_threaded_mainloop_lock(i->mainloop); + + i->sample_spec.channels = *(int*) argp ? 2 : 1; + free_stream(i); + + pa_threaded_mainloop_unlock(i->mainloop); + return 0; + + case SNDCTL_DSP_CHANNELS: { + pa_sample_spec ss; + int valid; + + debug(__FILE__": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp); + + pa_threaded_mainloop_lock(i->mainloop); + + ss = i->sample_spec; + ss.channels = *(int*) argp; + + if ((valid = pa_sample_spec_valid(&ss))) { + i->sample_spec = ss; + free_stream(i); + } + + pa_threaded_mainloop_unlock(i->mainloop); + + if (!valid) { + *_errno = EINVAL; + goto fail; + } + + break; + } + + case SNDCTL_DSP_GETBLKSIZE: + debug(__FILE__": SNDCTL_DSP_GETBLKSIZE\n"); + + pa_threaded_mainloop_lock(i->mainloop); + + fix_metrics(i); + *(int*) argp = i->fragment_size; + + pa_threaded_mainloop_unlock(i->mainloop); + + break; + + case SNDCTL_DSP_SETFRAGMENT: + debug(__FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%8x\n", *(int*) argp); + + pa_threaded_mainloop_lock(i->mainloop); + + i->fragment_size = 1 << (*(int*) argp); + i->n_fragments = (*(int*) argp) >> 16; + + free_stream(i); + + pa_threaded_mainloop_unlock(i->mainloop); + + break; + + case SNDCTL_DSP_GETCAPS: + debug(__FILE__": SNDCTL_DSP_CAPS\n"); + + *(int*) argp = DSP_CAP_MULTI; + break; + + case SNDCTL_DSP_GETODELAY: { + int l; + + debug(__FILE__": SNDCTL_DSP_GETODELAY\n"); + + pa_threaded_mainloop_lock(i->mainloop); + + *(int*) argp = 0; + + for (;;) { + pa_usec_t usec; + if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY) + break; + + if (pa_stream_get_latency(i->stream, &usec, NULL) >= 0) { + *(int*) argp = pa_usec_to_bytes(usec, &i->sample_spec); + break; + } + + if (pa_context_errno(i->context) != PA_ERR_NODATA) { + debug(__FILE__": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i->context))); + break; + } + + pa_threaded_mainloop_wait(i->mainloop); + } + + if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) + debug(__FILE__": SIOCINQ failed: %s\n", strerror(errno)); + else + *(int*) argp += l; + + pa_threaded_mainloop_unlock(i->mainloop); + + debug(__FILE__": ODELAY: %i\n", *(int*) argp); + + break; + } + + case SNDCTL_DSP_RESET: { + debug(__FILE__": SNDCTL_DSP_RESET\n"); + + pa_threaded_mainloop_lock(i->mainloop); + + free_stream(i); + reset_params(i); + + pa_threaded_mainloop_unlock(i->mainloop); + break; + } + + case SNDCTL_DSP_GETFMTS: { + debug(__FILE__": SNDCTL_DSP_GETFMTS\n"); + + *(int*) argp = AFMT_MU_LAW|AFMT_A_LAW|AFMT_U8|AFMT_S16_LE|AFMT_S16_BE; + break; + } + + case SNDCTL_DSP_POST: + debug(__FILE__": SNDCTL_DSP_POST\n"); + + if (dsp_trigger(i) < 0) + *_errno = EIO; + break; + + case SNDCTL_DSP_SYNC: + debug(__FILE__": SNDCTL_DSP_SYNC\n"); + + if (dsp_drain(i) < 0) + *_errno = EIO; + + break; + + case SNDCTL_DSP_GETOSPACE: { + audio_buf_info *bi = (audio_buf_info*) argp; + int l; + size_t k = 0; + + debug(__FILE__": SNDCTL_DSP_GETOSPACE\n"); + + pa_threaded_mainloop_lock(i->mainloop); + + fix_metrics(i); + + if (i->stream) { + if ((k = pa_stream_writable_size(i->stream)) == (size_t) -1) + debug(__FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); + } else + k = i->fragment_size * i->n_fragments; + + if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { + debug(__FILE__": SIOCINQ failed: %s\n", strerror(errno)); + l = 0; + } + + bi->fragsize = i->fragment_size; + bi->fragstotal = i->n_fragments; + bi->bytes = k > (size_t) l ? k - l : 0; + bi->fragments = bi->bytes / bi->fragsize; + + pa_threaded_mainloop_unlock(i->mainloop); + + debug(__FILE__": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi->fragsize, bi->fragstotal, bi->bytes, bi->fragments); + + break; + } + + default: + debug(__FILE__": unknwon ioctl 0x%08lx\n", request); + + *_errno = EINVAL; + goto fail; + } + + ret = 0; + +fail: + + return ret; +} + +int ioctl(int fd, unsigned long request, ...) { + fd_info *i; + va_list args; + void *argp; + int r, _errno = 0; + + debug(__FILE__": ioctl()\n"); + + va_start(args, request); + argp = va_arg(args, void *); + va_end(args); + + if (!function_enter()) { + LOAD_IOCTL_FUNC(); + return _ioctl(fd, request, argp); + } + + if (!(i = fd_info_find(fd))) { + function_exit(); + LOAD_IOCTL_FUNC(); + return _ioctl(fd, request, argp); + } + + if (i->type == FD_INFO_MIXER) + r = mixer_ioctl(i, request, argp, &_errno); + else + r = dsp_ioctl(i, request, argp, &_errno); + + fd_info_unref(i); + + if (_errno) + errno = _errno; + + function_exit(); + + return r; +} + +int close(int fd) { + fd_info *i; + + debug(__FILE__": close()\n"); + + if (!function_enter()) { + LOAD_CLOSE_FUNC(); + return _close(fd); + } + + if (!(i = fd_info_find(fd))) { + function_exit(); + LOAD_CLOSE_FUNC(); + return _close(fd); + } + + fd_info_remove_from_list(i); + fd_info_unref(i); + + function_exit(); + + return 0; +} + +int open64(const char *filename, int flags, ...) { + va_list args; + mode_t mode = 0; + + debug(__FILE__": open64()\n"); + + va_start(args, flags); + if (flags & O_CREAT) + mode = va_arg(args, mode_t); + va_end(args); + + if (strcmp(filename, "/dev/dsp") != 0 && + strcmp(filename, "/dev/adsp") != 0 && + strcmp(filename, "/dev/mixer") != 0) { + LOAD_OPEN64_FUNC(); + return _open64(filename, flags, mode); + } + + return open(filename, flags, mode); +} + +FILE* fopen(const char *filename, const char *mode) { + FILE *f = NULL; + int fd; + + debug(__FILE__": fopen()\n"); + + if (strcmp(filename, "/dev/dsp") != 0 && + strcmp(filename, "/dev/adsp") != 0 && + strcmp(filename, "/dev/mixer") != 0) { + LOAD_FOPEN_FUNC(); + return _fopen(filename, mode); + } + + if (strcmp(mode, "wb") != 0) { + errno = EACCES; + return NULL; + } + + if ((fd = open(filename, O_WRONLY)) < 0) + return NULL; + + if (!(f = fdopen(fd, "wb"))) { + close(fd); + return NULL; + } + + return f; +} + +FILE *fopen64(const char *filename, const char *mode) { + + debug(__FILE__": fopen64()\n"); + + if (strcmp(filename, "/dev/dsp") != 0 && + strcmp(filename, "/dev/adsp") != 0 && + strcmp(filename, "/dev/mixer") != 0) { + LOAD_FOPEN64_FUNC(); + return _fopen64(filename, mode); + } + + return fopen(filename, mode); +} + +int fclose(FILE *f) { + fd_info *i; + + debug(__FILE__": fclose()\n"); + + if (!function_enter()) { + LOAD_FCLOSE_FUNC(); + return _fclose(f); + } + + if (!(i = fd_info_find(fileno(f)))) { + function_exit(); + LOAD_FCLOSE_FUNC(); + return _fclose(f); + } + + fd_info_remove_from_list(i); + + /* Dirty trick to avoid that the fd is not freed twice, once by us + * and once by the real fclose() */ + i->app_fd = -1; + + fd_info_unref(i); + + function_exit(); + + LOAD_FCLOSE_FUNC(); + return _fclose(f); +} -- cgit From 7906985d2af27a187eac7260f641a07c39bb705e Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 23 May 2006 15:24:29 +0000 Subject: Cast size_t to long to be more compatible with 64-bit systems. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@951 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 06bdd575..63f79eb1 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -417,7 +417,7 @@ static void fix_metrics(fd_info *i) { i->fragment_size = 1024; debug(__FILE__": sample spec: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); - debug(__FILE__": fixated metrics to %i fragments, %i bytes each.\n", i->n_fragments, i->fragment_size); + debug(__FILE__": fixated metrics to %i fragments, %li bytes each.\n", i->n_fragments, (long)i->fragment_size); } static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { -- cgit From e99afdae388018f119c16c3a331e01898ab9a90a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 May 2006 16:37:33 +0000 Subject: pass the binary name as client name to polypaudio git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@952 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 63f79eb1..ec073a28 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -278,9 +278,21 @@ static void reset_params(fd_info *i) { i->n_fragments = 0; } +static char *client_name(char *buf, size_t n) { + char p[PATH_MAX]; + + if (pa_get_binary_name(p, sizeof(p))) + snprintf(buf, n, "oss[%s]", pa_path_get_filename(p)); + else + snprintf(buf, n, "oss"); + + return buf; +} + static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { fd_info *i; int sfds[2] = { -1, -1 }; + char name[64]; debug(__FILE__": fd_info_new()\n"); @@ -320,7 +332,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { goto fail; } - if (!(i->context = pa_context_new(pa_threaded_mainloop_get_api(i->mainloop), "oss"))) { + if (!(i->context = pa_context_new(pa_threaded_mainloop_get_api(i->mainloop), client_name(name, sizeof(name))))) { *_errno = EIO; debug(__FILE__": pa_context_new() failed\n"); goto fail; -- cgit From 23b123d361959553fc9e467dd4b605adee00f07e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 May 2006 23:06:28 +0000 Subject: - use pthread_atfork() to disable open sound streams in the child after a fork. Obviusly sound won't work in child process but at least we don't leak fds from the parent. Now any operation on the device fd in the child will result in an EBADF error, which seems somewhat clean to me. - flush our unix socket properly on RESET ioctl git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@953 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 122 insertions(+), 6 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index ec073a28..a69676ab 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -60,6 +60,7 @@ typedef struct fd_info fd_info; struct fd_info { pthread_mutex_t mutex; int ref; + int unusable; fd_info_type_t type; int app_fd, thread_fd; @@ -82,6 +83,7 @@ struct fd_info { }; static int dsp_drain(fd_info *i); +static void fd_info_remove_from_list(fd_info *i); static pthread_mutex_t fd_infos_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t func_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -289,14 +291,101 @@ static char *client_name(char *buf, size_t n) { return buf; } +static void atfork_prepare(void) { + fd_info *i; + + debug(__FILE__": atfork_prepare() enter\n"); + + function_enter(); + + pthread_mutex_lock(&fd_infos_mutex); + + for (i = fd_infos; i; i = i->next) { + pthread_mutex_lock(&i->mutex); + pa_threaded_mainloop_lock(i->mainloop); + } + + pthread_mutex_lock(&func_mutex); + + + debug(__FILE__": atfork_prepare() exit\n"); +} + +static void atfork_parent(void) { + fd_info *i; + + debug(__FILE__": atfork_parent() enter\n"); + + pthread_mutex_unlock(&func_mutex); + + for (i = fd_infos; i; i = i->next) { + pa_threaded_mainloop_unlock(i->mainloop); + pthread_mutex_unlock(&i->mutex); + } + + pthread_mutex_unlock(&fd_infos_mutex); + + function_exit(); + + debug(__FILE__": atfork_parent() exit\n"); +} + +static void atfork_child(void) { + fd_info *i; + + debug(__FILE__": atfork_child() enter\n"); + + /* We do only the bare minimum to get all fds closed */ + pthread_mutex_init(&func_mutex, NULL); + pthread_mutex_init(&fd_infos_mutex, NULL); + + for (i = fd_infos; i; i = i->next) { + pthread_mutex_init(&i->mutex, NULL); + + if (i->context) { + pa_context_disconnect(i->context); + pa_context_unref(i->context); + i->context = NULL; + } + + if (i->stream) { + pa_stream_unref(i->stream); + i->stream = NULL; + } + + if (i->app_fd >= 0) { + close(i->app_fd); + i->app_fd = -1; + } + + if (i->thread_fd >= 0) { + close(i->thread_fd); + i->thread_fd = -1; + } + + i->unusable = 1; + } + + function_exit(); + + debug(__FILE__": atfork_child() exit\n"); +} + +static void install_atfork(void) { + pthread_atfork(atfork_prepare, atfork_parent, atfork_child); +} + static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { fd_info *i; int sfds[2] = { -1, -1 }; char name[64]; + static pthread_once_t install_atfork_once = PTHREAD_ONCE_INIT; debug(__FILE__": fd_info_new()\n"); signal(SIGPIPE, SIG_IGN); /* Yes, ugly as hell */ + + pthread_once(&install_atfork_once, install_atfork); if (!(i = malloc(sizeof(fd_info)))) { *_errno = ENOMEM; @@ -313,6 +402,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { pthread_mutex_init(&i->mutex, NULL); i->ref = 1; i->buf = NULL; + i->unusable = 0; PA_LLIST_INIT(fd_info, i); reset_params(i); @@ -404,7 +494,7 @@ static fd_info* fd_info_find(int fd) { pthread_mutex_lock(&fd_infos_mutex); for (i = fd_infos; i; i = i->next) - if (i->app_fd == fd) { + if (i->app_fd == fd && !i->unusable) { fd_info_ref(i); break; } @@ -546,7 +636,7 @@ static int create_stream(fd_info *i) { fix_metrics(i); - if (!(i->stream = pa_stream_new(i->context, "audio stream", &i->sample_spec, NULL))) { + if (!(i->stream = pa_stream_new(i->context, "Audio Stream", &i->sample_spec, NULL))) { debug(__FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -784,6 +874,30 @@ static void success_cb(pa_stream *s, int success, void *userdata) { pa_threaded_mainloop_signal(i->mainloop, 0); } +static int dsp_flush_socket(fd_info *i) { + int l; + + if (i->thread_fd < 0) + return -1; + + if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { + debug(__FILE__": SIOCINQ: %s\n", strerror(errno)); + return -1; + } + + while (l > 0) { + char buf[1024]; + size_t k; + + k = (size_t) l > sizeof(buf) ? sizeof(buf) : (size_t) l; + if (read(i->thread_fd, buf, k) < 0) + debug(__FILE__": read(): %s\n", strerror(errno)); + l -= k; + } + + return 0; +} + static int dsp_empty_socket(fd_info *i) { int ret = -1; @@ -791,7 +905,7 @@ static int dsp_empty_socket(fd_info *i) { for (;;) { int l; - if (i->thread_fd < 0) + if (i->thread_fd < 0 || !i->stream) break; if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { @@ -861,8 +975,6 @@ static int dsp_trigger(fd_info *i) { pa_operation *o = NULL; int r = -1; - fd_info_copy_data(i, 1); - if (!i->stream) return 0; @@ -926,6 +1038,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_SPEED: { pa_sample_spec ss; int valid; + char t[256]; debug(__FILE__": SNDCTL_DSP_SPEED: %i\n", *(int*) argp); @@ -939,13 +1052,15 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) free_stream(i); } + debug(__FILE__": ss: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); + pa_threaded_mainloop_unlock(i->mainloop); if (!valid) { *_errno = EINVAL; goto fail; } - + break; } @@ -1063,6 +1178,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_lock(i->mainloop); free_stream(i); + dsp_flush_socket(i); reset_params(i); pa_threaded_mainloop_unlock(i->mainloop); -- cgit From 46fee4641864df8972beb95f9d9af5670198add9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 May 2006 23:57:50 +0000 Subject: implement emulation of /dev/sndstat git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@954 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 102 insertions(+), 15 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index a69676ab..ed34ac8a 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -771,11 +771,83 @@ static int mixer_open(int flags, int *_errno) { } +static int sndstat_open(int flags, int *_errno) { + static const char sndstat[] = + "Sound Driver:3.8.1a-980706 (Polypaudio Virtual OSS)\n" + "Kernel: POSIX\n" + "Config options: 0\n" + "\n" + "Installed drivers:\n" + "Type 255: Polypaudio Virtual OSS\n" + "\n" + "Card config:\n" + "Polypaudio Virtual OSS\n" + "\n" + "Audio devices:\n" + "0: Polypaudio Virtual OSS\n" + "\n" + "Synth devices: NOT ENABLED IN CONFIG\n" + "\n" + "Midi devices:\n" + "\n" + "Timers:\n" + "\n" + "\Mixers:\n" + "0: Polypaudio Virtual OSS\n"; + + char fn[] = "/tmp/padsp-sndstat-XXXXXX"; + mode_t u; + int fd = -1; + int e; + + debug(__FILE__": sndstat_open()\n"); + + if (flags != O_RDONLY && flags != (O_RDONLY|O_LARGEFILE)) { + *_errno = EACCES; + debug(__FILE__": bad access!\n"); + goto fail; + } + + u = umask(0077); + fd = mkstemp(fn); + e = errno; + umask(u); + + if (fd < 0) { + *_errno = e; + debug(__FILE__": mkstemp() failed: %s\n", strerror(errno)); + goto fail; + } + + unlink(fn); + + if (write(fd, sndstat, sizeof(sndstat) -1) != sizeof(sndstat)-1) { + *_errno = errno; + debug(__FILE__": write() failed: %s\n", strerror(errno)); + goto fail; + } + + if (lseek(fd, SEEK_SET, 0) < 0) { + *_errno = errno; + debug(__FILE__": lseek() failed: %s\n", strerror(errno)); + goto fail; + } + + return fd; + +fail: + if (fd >= 0) + close(fd); + return -1; +} + int open(const char *filename, int flags, ...) { va_list args; mode_t mode = 0; int r, _errno = 0; + debug(__FILE__": open(%s)\n", filename); + va_start(args, flags); if (flags & O_CREAT) mode = va_arg(args, mode_t); @@ -786,12 +858,12 @@ int open(const char *filename, int flags, ...) { return _open(filename, flags, mode); } - debug(__FILE__": open()\n"); - if (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0) { r = dsp_open(flags, &_errno); } else if (strcmp(filename, "/dev/mixer") == 0) { r = mixer_open(flags, &_errno); + } else if (strcmp(filename, "/dev/sndstat") == 0) { + r = sndstat_open(flags, &_errno); } else { function_exit(); LOAD_OPEN_FUNC(); @@ -1321,7 +1393,7 @@ int open64(const char *filename, int flags, ...) { va_list args; mode_t mode = 0; - debug(__FILE__": open64()\n"); + debug(__FILE__": open64(%s)\n", filename); va_start(args, flags); if (flags & O_CREAT) @@ -1330,6 +1402,7 @@ int open64(const char *filename, int flags, ...) { if (strcmp(filename, "/dev/dsp") != 0 && strcmp(filename, "/dev/adsp") != 0 && + strcmp(filename, "/dev/sndstat") != 0 && strcmp(filename, "/dev/mixer") != 0) { LOAD_OPEN64_FUNC(); return _open64(filename, flags, mode); @@ -1341,25 +1414,38 @@ int open64(const char *filename, int flags, ...) { FILE* fopen(const char *filename, const char *mode) { FILE *f = NULL; int fd; + mode_t m; + + debug(__FILE__": fopen(%s)\n", filename); - debug(__FILE__": fopen()\n"); + if (strcmp(filename, "/dev/dsp") == 0 || + strcmp(filename, "/dev/adsp") == 0) { - if (strcmp(filename, "/dev/dsp") != 0 && - strcmp(filename, "/dev/adsp") != 0 && - strcmp(filename, "/dev/mixer") != 0) { + if (strcmp(mode, "wb") != 0) { + errno = EACCES; + return NULL; + } + + m = O_WRONLY; + } else if (strcmp(filename, "/dev/sndstat") == 0) { + + if (strcmp(mode, "r") != 0) { + errno = EACCES; + return NULL; + } + + m = O_RDONLY; + } else if (strcmp(filename, "/dev/mixer") != 0) + m = O_RDWR; + else { LOAD_FOPEN_FUNC(); return _fopen(filename, mode); } - if (strcmp(mode, "wb") != 0) { - errno = EACCES; - return NULL; - } - - if ((fd = open(filename, O_WRONLY)) < 0) + if ((fd = open(filename, m)) < 0) return NULL; - if (!(f = fdopen(fd, "wb"))) { + if (!(f = fdopen(fd, mode))) { close(fd); return NULL; } @@ -1369,10 +1455,11 @@ FILE* fopen(const char *filename, const char *mode) { FILE *fopen64(const char *filename, const char *mode) { - debug(__FILE__": fopen64()\n"); + debug(__FILE__": fopen64(%s)\n", filename); if (strcmp(filename, "/dev/dsp") != 0 && strcmp(filename, "/dev/adsp") != 0 && + strcmp(filename, "/dev/sndstat") != 0 && strcmp(filename, "/dev/mixer") != 0) { LOAD_FOPEN64_FUNC(); return _fopen64(filename, mode); -- cgit From 440b901a4d445de6695e3fa41853a694d677516e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 May 2006 00:42:30 +0000 Subject: fix playback of small sound files git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@955 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index ed34ac8a..d9325df4 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -977,7 +977,7 @@ static int dsp_empty_socket(fd_info *i) { for (;;) { int l; - if (i->thread_fd < 0 || !i->stream) + if (i->thread_fd < 0) break; if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { @@ -985,8 +985,10 @@ static int dsp_empty_socket(fd_info *i) { break; } - if (!l) + if (!l) { + ret = 0; break; + } pa_threaded_mainloop_wait(i->mainloop); } -- cgit From ca08e57470d0a6ce1bcbfb853288aa7d3a08efe1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 May 2006 02:13:29 +0000 Subject: implement a /dev/mixer interface git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@956 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 286 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 261 insertions(+), 25 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index d9325df4..b85d9c4d 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -79,6 +79,10 @@ struct fd_info { int operation_success; + pa_cvolume volume; + uint32_t sink_index; + int volume_modify_count; + PA_LLIST_FIELDS(fd_info); }; @@ -154,6 +158,21 @@ do { \ pthread_mutex_unlock(&func_mutex); \ } while(0) +#define CONTEXT_CHECK_DEAD_GOTO(i, label) do { \ +if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \ + debug(__FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ + goto label; \ +} \ +} while(0); + +#define STREAM_CHECK_DEAD_GOTO(i, label) do { \ +if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ + !(i)->stream || pa_stream_get_state((i)->stream) != PA_STREAM_READY) { \ + debug(__FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ + goto label; \ +} \ +} while(0); + static void debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); static void debug(const char *format, ...) { @@ -375,6 +394,26 @@ static void install_atfork(void) { pthread_atfork(atfork_prepare, atfork_parent, atfork_child); } +static void stream_success_cb(pa_stream *s, int success, void *userdata) { + fd_info *i = userdata; + + assert(s); + assert(i); + + i->operation_success = success; + pa_threaded_mainloop_signal(i->mainloop, 0); +} + +static void context_success_cb(pa_context *c, int success, void *userdata) { + fd_info *i = userdata; + + assert(c); + assert(i); + + i->operation_success = success; + pa_threaded_mainloop_signal(i->mainloop, 0); +} + static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { fd_info *i; int sfds[2] = { -1, -1 }; @@ -403,6 +442,9 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { i->ref = 1; i->buf = NULL; i->unusable = 0; + pa_cvolume_reset(&i->volume, 2); + i->volume_modify_count = 0; + i->sink_index = (uint32_t) -1; PA_LLIST_INIT(fd_info, i); reset_params(i); @@ -760,15 +802,118 @@ fail: return -1; } +static void sink_info_cb(pa_context *context, const pa_sink_info *si, int eol, void *userdata) { + fd_info *i = userdata; + + if (!si && eol < 0) { + i->operation_success = 0; + pa_threaded_mainloop_signal(i->mainloop, 0); + return; + } + + if (eol) + return; + + if (!pa_cvolume_equal(&i->volume, &si->volume)) + i->volume_modify_count++; + + i->volume = si->volume; + i->sink_index = si->index; + + i->operation_success = 1; + pa_threaded_mainloop_signal(i->mainloop, 0); +} + +static void subscribe_cb(pa_context *context, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { + fd_info *i = userdata; + pa_operation *o = NULL; + + if (i->sink_index != idx) + return; + + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE) + return; + + if (!(o = pa_context_get_sink_info_by_index(i->context, i->sink_index, sink_info_cb, i))) { + debug(__FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); + return; + } + + pa_operation_unref(o); +} + static int mixer_open(int flags, int *_errno) { -/* fd_info *i; */ + fd_info *i; + pa_operation *o; + int ret; - *_errno = ENOSYS; - return -1; + if (!(i = fd_info_new(FD_INFO_MIXER, _errno))) + return -1; + + pa_threaded_mainloop_lock(i->mainloop); + + pa_context_set_subscribe_callback(i->context, subscribe_cb, i); + + if (!(o = pa_context_subscribe(i->context, PA_SUBSCRIPTION_MASK_SINK, context_success_cb, i))) { + debug(__FILE__": Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); + *_errno = EIO; + goto fail; + } + + i->operation_success = 0; + while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(i->mainloop); + CONTEXT_CHECK_DEAD_GOTO(i, fail); + } + + if (!i->operation_success) { + debug(__FILE__":Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); + *_errno = EIO; + goto fail; + } + + /* Get sink info */ + + pa_operation_unref(o); + if (!(o = pa_context_get_sink_info_by_name(i->context, NULL, sink_info_cb, i))) { + debug(__FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); + *_errno = EIO; + goto fail; + } -/* if (!(i = fd_info_new(FD_INFO_MIXER))) */ -/* return -1; */ + i->operation_success = 0; + while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(i->mainloop); + CONTEXT_CHECK_DEAD_GOTO(i, fail); + } + + if (!i->operation_success) { + debug(__FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); + *_errno = EIO; + goto fail; + } + + pa_threaded_mainloop_unlock(i->mainloop); + + debug(__FILE__": mixer_open() succeeded, fd=%i\n", i->app_fd); + + fd_info_add_to_list(i); + ret = i->app_fd; + fd_info_unref(i); + + return ret; + +fail: + pa_threaded_mainloop_unlock(i->mainloop); + if (i) + fd_info_unref(i); + + *_errno = EIO; + + debug(__FILE__": mixer_open() failed\n"); + + return -1; } static int sndstat_open(int flags, int *_errno) { @@ -879,8 +1024,109 @@ int open(const char *filename, int flags, ...) { } static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { - *_errno = ENOSYS; - return -1; + int ret = -1; + + switch (request) { + case SOUND_MIXER_READ_DEVMASK : + debug(__FILE__": SOUND_MIXER_READ_DEVMASK\n"); + + *(int*) argp = SOUND_MASK_PCM; + break; + + case SOUND_MIXER_READ_RECMASK : + debug(__FILE__": SOUND_MIXER_READ_RECMASK\n"); + + *(int*) argp = 0; + break; + + case SOUND_MIXER_READ_STEREODEVS: + debug(__FILE__": SOUND_MIXER_READ_STEREODEVS\n"); + + pa_threaded_mainloop_lock(i->mainloop); + *(int*) argp = i->volume.channels > 1 ? SOUND_MASK_PCM : 0; + pa_threaded_mainloop_unlock(i->mainloop); + + break; + + case SOUND_MIXER_READ_RECSRC: + debug(__FILE__": SOUND_MIXER_READ_RECSRC\n"); + + *(int*) argp = 0; + break; + + case SOUND_MIXER_CAPS: + debug(__FILE__": SOUND_MIXER_CAPS\n"); + + *(int*) argp = 0; + break; + + case SOUND_MIXER_READ_PCM: + + debug(__FILE__": SOUND_MIXER_READ_PCM\n"); + + pa_threaded_mainloop_lock(i->mainloop); + + *(int*) argp = + ((i->volume.values[0]*100/PA_VOLUME_NORM) << 8) | + ((i->volume.values[i->volume.channels > 1 ? 1 : 0]*100/PA_VOLUME_NORM)); + + pa_threaded_mainloop_unlock(i->mainloop); + + break; + + case SOUND_MIXER_WRITE_PCM: { + pa_cvolume v; + + debug(__FILE__": SOUND_MIXER_WRITE_PCM\n"); + + pa_threaded_mainloop_lock(i->mainloop); + + v = i->volume; + + i->volume.values[0] = ((*(int*) argp >> 8)*PA_VOLUME_NORM)/100; + i->volume.values[1] = ((*(int*) argp & 0xFF)*PA_VOLUME_NORM)/100; + + if (!pa_cvolume_equal(&i->volume, &v)) { + pa_operation *o; + + if (!(o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, &i->volume, NULL, NULL))) + debug(__FILE__":Failed set volume: %s", pa_strerror(pa_context_errno(i->context))); + else + pa_operation_unref(o); + + /* We don't wait for completion here */ + i->volume_modify_count++; + } + + pa_threaded_mainloop_unlock(i->mainloop); + + break; + } + + case SOUND_MIXER_INFO: { + mixer_info *mi = argp; + + memset(mi, 0, sizeof(mixer_info)); + strncpy(mi->id, "POLYPAUDIO", sizeof(mi->id)); + strncpy(mi->name, "Polypaudio Virtual OSS", sizeof(mi->name)); + pa_threaded_mainloop_lock(i->mainloop); + mi->modify_counter = i->volume_modify_count; + pa_threaded_mainloop_unlock(i->mainloop); + break; + } + + default: + debug(__FILE__": unknwon ioctl 0x%08lx\n", request); + + *_errno = EINVAL; + goto fail; + } + + ret = 0; + +fail: + + return ret; } static int map_format(int *fmt, pa_sample_spec *ss) { @@ -936,16 +1182,6 @@ static int map_format_back(pa_sample_format_t format) { } } -static void success_cb(pa_stream *s, int success, void *userdata) { - fd_info *i = userdata; - - assert(s); - assert(i); - - i->operation_success = success; - pa_threaded_mainloop_signal(i->mainloop, 0); -} - static int dsp_flush_socket(fd_info *i) { int l; @@ -1015,15 +1251,14 @@ static int dsp_drain(fd_info *i) { debug(__FILE__": Really draining.\n"); - if (!(o = pa_stream_drain(i->stream, success_cb, i))) { + if (!(o = pa_stream_drain(i->stream, stream_success_cb, i))) { debug(__FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } i->operation_success = 0; while (pa_operation_get_state(o) != PA_OPERATION_DONE) { - if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY) - goto fail; + STREAM_CHECK_DEAD_GOTO(i, fail); pa_threaded_mainloop_wait(i->mainloop); } @@ -1059,15 +1294,14 @@ static int dsp_trigger(fd_info *i) { debug(__FILE__": Triggering.\n"); - if (!(o = pa_stream_trigger(i->stream, success_cb, i))) { + if (!(o = pa_stream_trigger(i->stream, stream_success_cb, i))) { debug(__FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } i->operation_success = 0; while (!pa_operation_get_state(o) != PA_OPERATION_DONE) { - if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY) - goto fail; + STREAM_CHECK_DEAD_GOTO(i, fail); pa_threaded_mainloop_wait(i->mainloop); } @@ -1218,8 +1452,8 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) for (;;) { pa_usec_t usec; - if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY) - break; + + STREAM_CHECK_DEAD_GOTO(i, exit_loop); if (pa_stream_get_latency(i->stream, &usec, NULL) >= 0) { *(int*) argp = pa_usec_to_bytes(usec, &i->sample_spec); @@ -1234,6 +1468,8 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_wait(i->mainloop); } + exit_loop: + if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) debug(__FILE__": SIOCINQ failed: %s\n", strerror(errno)); else -- cgit From c4328cdfddb16cf43ae4037b087cf2c58d7c531d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 24 May 2006 08:14:19 +0000 Subject: Fix stray \ git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@957 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index b85d9c4d..10b08eae 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -937,7 +937,7 @@ static int sndstat_open(int flags, int *_errno) { "\n" "Timers:\n" "\n" - "\Mixers:\n" + "Mixers:\n" "0: Polypaudio Virtual OSS\n"; char fn[] = "/tmp/padsp-sndstat-XXXXXX"; -- cgit From 3fa19ab457ff71d148a6dff5eb7362582e82ce61 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 24 May 2006 13:23:15 +0000 Subject: Fix warnings. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@959 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 10b08eae..87d0b257 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -102,11 +102,18 @@ static int (*_open64)(const char *, int, mode_t) = NULL; static FILE* (*_fopen64)(const char *path, const char *mode) = NULL; static int (*_fclose)(FILE *f) = NULL; +/* dlsym() violates ISO C, so confide the breakage into this function to + * avoid warnings. */ +typedef void (*fnptr)(void); +static inline fnptr dlsym_fn(void *handle, const char *symbol) { + return (fnptr) (long) dlsym(handle, symbol); +} + #define LOAD_IOCTL_FUNC() \ do { \ pthread_mutex_lock(&func_mutex); \ if (!_ioctl) \ - _ioctl = (int (*)(int, int, void*)) dlsym(RTLD_NEXT, "ioctl"); \ + _ioctl = (int (*)(int, int, void*)) dlsym_fn(RTLD_NEXT, "ioctl"); \ pthread_mutex_unlock(&func_mutex); \ } while(0) @@ -114,7 +121,7 @@ do { \ do { \ pthread_mutex_lock(&func_mutex); \ if (!_open) \ - _open = (int (*)(const char *, int, mode_t)) dlsym(RTLD_NEXT, "open"); \ + _open = (int (*)(const char *, int, mode_t)) dlsym_fn(RTLD_NEXT, "open"); \ pthread_mutex_unlock(&func_mutex); \ } while(0) @@ -122,7 +129,7 @@ do { \ do { \ pthread_mutex_lock(&func_mutex); \ if (!_open64) \ - _open64 = (int (*)(const char *, int, mode_t)) dlsym(RTLD_NEXT, "open64"); \ + _open64 = (int (*)(const char *, int, mode_t)) dlsym_fn(RTLD_NEXT, "open64"); \ pthread_mutex_unlock(&func_mutex); \ } while(0) @@ -130,7 +137,7 @@ do { \ do { \ pthread_mutex_lock(&func_mutex); \ if (!_close) \ - _close = (int (*)(int)) dlsym(RTLD_NEXT, "close"); \ + _close = (int (*)(int)) dlsym_fn(RTLD_NEXT, "close"); \ pthread_mutex_unlock(&func_mutex); \ } while(0) @@ -138,7 +145,7 @@ do { \ do { \ pthread_mutex_lock(&func_mutex); \ if (!_fopen) \ - _fopen = (FILE* (*)(const char *, const char*)) dlsym(RTLD_NEXT, "fopen"); \ + _fopen = (FILE* (*)(const char *, const char*)) dlsym_fn(RTLD_NEXT, "fopen"); \ pthread_mutex_unlock(&func_mutex); \ } while(0) @@ -146,7 +153,7 @@ do { \ do { \ pthread_mutex_lock(&func_mutex); \ if (!_fopen64) \ - _fopen64 = (FILE* (*)(const char *, const char*)) dlsym(RTLD_NEXT, "fopen64"); \ + _fopen64 = (FILE* (*)(const char *, const char*)) dlsym_fn(RTLD_NEXT, "fopen64"); \ pthread_mutex_unlock(&func_mutex); \ } while(0) @@ -154,7 +161,7 @@ do { \ do { \ pthread_mutex_lock(&func_mutex); \ if (!_fclose) \ - _fclose = (int (*)(FILE *)) dlsym(RTLD_NEXT, "fclose"); \ + _fclose = (int (*)(FILE *)) dlsym_fn(RTLD_NEXT, "fclose"); \ pthread_mutex_unlock(&func_mutex); \ } while(0) -- cgit From 59d00e2f49f709630cd3c55b28e752fa5d7919fb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 00:25:03 +0000 Subject: * issue volume updates syncrhonously * correct channel order of OSS volumes (swap left,right) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@962 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 87d0b257..d372b697 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1074,8 +1074,8 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno pa_threaded_mainloop_lock(i->mainloop); *(int*) argp = - ((i->volume.values[0]*100/PA_VOLUME_NORM) << 8) | - ((i->volume.values[i->volume.channels > 1 ? 1 : 0]*100/PA_VOLUME_NORM)); + ((i->volume.values[0]*100/PA_VOLUME_NORM)) | + ((i->volume.values[i->volume.channels > 1 ? 1 : 0]*100/PA_VOLUME_NORM) << 8); pa_threaded_mainloop_unlock(i->mainloop); @@ -1090,16 +1090,29 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno v = i->volume; - i->volume.values[0] = ((*(int*) argp >> 8)*PA_VOLUME_NORM)/100; - i->volume.values[1] = ((*(int*) argp & 0xFF)*PA_VOLUME_NORM)/100; + i->volume.values[0] = ((*(int*) argp & 0xFF)*PA_VOLUME_NORM)/100; + i->volume.values[1] = ((*(int*) argp >> 8)*PA_VOLUME_NORM)/100; if (!pa_cvolume_equal(&i->volume, &v)) { pa_operation *o; if (!(o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, &i->volume, NULL, NULL))) debug(__FILE__":Failed set volume: %s", pa_strerror(pa_context_errno(i->context))); - else + else { + + i->operation_success = 0; + while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + CONTEXT_CHECK_DEAD_GOTO(i, exit_loop); + + pa_threaded_mainloop_wait(i->mainloop); + } + exit_loop: + + if (!i->operation_success) + debug(__FILE__": Failed to set volume: %s\n", pa_strerror(pa_context_errno(i->context))); + pa_operation_unref(o); + } /* We don't wait for completion here */ i->volume_modify_count++; -- cgit From 2bb05ea6678ff27f37ac082d01dcb9fd14889613 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 00:40:04 +0000 Subject: fix evil, evil typo that cause all gtk2 based apps to crash git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@963 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index d372b697..746965d7 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1693,7 +1693,7 @@ FILE* fopen(const char *filename, const char *mode) { } m = O_RDONLY; - } else if (strcmp(filename, "/dev/mixer") != 0) + } else if (strcmp(filename, "/dev/mixer") == 0) m = O_RDWR; else { LOAD_FOPEN_FUNC(); -- cgit From 2bbd7bac63a48361d3d848ba1d3838a0ef5eb2bd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 01:14:06 +0000 Subject: add support to disable emulation of /dev/dsp,/dev/mixer,/dev/sndstat selectively by either passing an environment variable or by defining a symbol __padsp_disable__ in the process git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@964 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 746965d7..2f0f7260 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -191,6 +191,61 @@ static void debug(const char *format, ...) { } } +static int padsp_disabled(void) { + static int *sym; + static int sym_resolved = 0; + + /* If the current process has a symbol __padsp_disabled__ we use + * it to detect whether we should enable our stuff or not. A + * program needs to be compiled with -rdynamic for this to work! + * The symbol must be an int containing a three bit bitmask: bit 1 + * -> disable /dev/dsp emulation, bit 2 -> disable /dev/sndstat + * emulation, bit 3 -> disable /dev/mixer emulation. Hence a value + * 7 disables padsp entirely. */ + + pthread_mutex_lock(&func_mutex); + if (!sym_resolved) { + sym = (int*) dlsym_fn(RTLD_DEFAULT, "__padsp_disabled__"); + sym_resolved = 1; + + } + pthread_mutex_unlock(&func_mutex); + + if (!sym) + return 0; + + return *sym; +} + +static int dsp_cloak_enable(void) { + if (padsp_disabled() & 1) + return 0; + + if (getenv("PADSP_NO_DSP")) + return 0; + + return 1; +} + +static int sndstat_cloak_enable(void) { + if (padsp_disabled() & 2) + return 0; + + if (getenv("PADSP_NO_SNDSTAT")) + return 0; + + return 1; +} + +static int mixer_cloak_enable(void) { + if (padsp_disabled() & 4) + return 0; + + if (getenv("PADSP_NO_MIXER")) + return 0; + + return 1; +} static pthread_key_t recursion_key; static void recursion_key_alloc(void) { @@ -1010,11 +1065,11 @@ int open(const char *filename, int flags, ...) { return _open(filename, flags, mode); } - if (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0) { + if (dsp_cloak_enable() && (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0)) { r = dsp_open(flags, &_errno); - } else if (strcmp(filename, "/dev/mixer") == 0) { + } else if (mixer_cloak_enable() && strcmp(filename, "/dev/mixer") == 0) { r = mixer_open(flags, &_errno); - } else if (strcmp(filename, "/dev/sndstat") == 0) { + } else if (sndstat_cloak_enable() && strcmp(filename, "/dev/sndstat") == 0) { r = sndstat_open(flags, &_errno); } else { function_exit(); -- cgit From ae80ab396e9aa764b16b436b7b7c66011dce513c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 01:19:56 +0000 Subject: read stream and client name from $PADSP_STREAM_NAME resp. $PADSP_CLIENT_NAME, if available git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@965 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 2f0f7260..5987ec5f 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -201,7 +201,7 @@ static int padsp_disabled(void) { * The symbol must be an int containing a three bit bitmask: bit 1 * -> disable /dev/dsp emulation, bit 2 -> disable /dev/sndstat * emulation, bit 3 -> disable /dev/mixer emulation. Hence a value - * 7 disables padsp entirely. */ + * of 7 disables padsp entirely. */ pthread_mutex_lock(&func_mutex); if (!sym_resolved) { @@ -363,15 +363,28 @@ static void reset_params(fd_info *i) { static char *client_name(char *buf, size_t n) { char p[PATH_MAX]; + const char *e; + + if ((e = getenv("PADSP_CLIENT_NAME"))) + return e; if (pa_get_binary_name(p, sizeof(p))) - snprintf(buf, n, "oss[%s]", pa_path_get_filename(p)); + snprintf(buf, n, "OSS Emulation[%s]", pa_path_get_filename(p)); else - snprintf(buf, n, "oss"); + snprintf(buf, n, "OSS"); return buf; } +static char *stream_name(void) { + const char *e; + + if ((e = getenv("PADSP_STREAM_NAME"))) + return e; + + return "Audio Stream"; +} + static void atfork_prepare(void) { fd_info *i; @@ -740,7 +753,7 @@ static int create_stream(fd_info *i) { fix_metrics(i); - if (!(i->stream = pa_stream_new(i->context, "Audio Stream", &i->sample_spec, NULL))) { + if (!(i->stream = pa_stream_new(i->context, stream_name(), &i->sample_spec, NULL))) { debug(__FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } -- cgit From 4413b89d7a45587b545a31463ad2196767f45563 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 17:16:55 +0000 Subject: * split pa_cstrerror() into its own file polypcore/core-error.[ch] * fix building of padsp * remove a warning when compiling padsp.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@972 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 5987ec5f..c1cc9c92 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -361,7 +361,7 @@ static void reset_params(fd_info *i) { i->n_fragments = 0; } -static char *client_name(char *buf, size_t n) { +static const char *client_name(char *buf, size_t n) { char p[PATH_MAX]; const char *e; @@ -376,7 +376,7 @@ static char *client_name(char *buf, size_t n) { return buf; } -static char *stream_name(void) { +static const char *stream_name(void) { const char *e; if ((e = getenv("PADSP_STREAM_NAME"))) -- cgit From f3b72593b545c66eeb5c7858958f0b2c44fd730e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 17:18:42 +0000 Subject: really fix a superfluous warning when building padsp.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@973 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index c1cc9c92..5f3f9158 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -205,7 +205,7 @@ static int padsp_disabled(void) { pthread_mutex_lock(&func_mutex); if (!sym_resolved) { - sym = (int*) dlsym_fn(RTLD_DEFAULT, "__padsp_disabled__"); + sym = (int*) dlsym(RTLD_DEFAULT, "__padsp_disabled__"); sym_resolved = 1; } -- cgit From 7d90e3a32d52a5d94b536c0286d3e87f4df01fd0 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 26 May 2006 09:21:03 +0000 Subject: Fix typos. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@980 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 5f3f9158..b3e443d3 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1129,8 +1129,8 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno *(int*) argp = 0; break; - case SOUND_MIXER_CAPS: - debug(__FILE__": SOUND_MIXER_CAPS\n"); + case SOUND_MIXER_READ_CAPS: + debug(__FILE__": SOUND_MIXER_READ_CAPS\n"); *(int*) argp = 0; break; @@ -1204,7 +1204,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno } default: - debug(__FILE__": unknwon ioctl 0x%08lx\n", request); + debug(__FILE__": unknown ioctl 0x%08lx\n", request); *_errno = EINVAL; goto fail; -- cgit From 12dc4c21ac4e31becf687513ac9852a3ae6893e5 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 26 May 2006 12:18:07 +0000 Subject: Fix the fix_metrics() function so that we don't get a tiny buffer by default. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@981 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index b3e443d3..8bad126b 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -357,7 +357,7 @@ static void reset_params(fd_info *i) { i->sample_spec.format = PA_SAMPLE_ULAW; i->sample_spec.channels = 1; i->sample_spec.rate = 8000; - i->fragment_size = 1024; + i->fragment_size = 0; i->n_fragments = 0; } @@ -627,13 +627,23 @@ static void fix_metrics(fd_info *i) { fs = pa_frame_size(&i->sample_spec); i->fragment_size = (i->fragment_size/fs)*fs; - - if (i->n_fragments < 2) - i->n_fragments = 12; - if (i->fragment_size <= 0) - if ((i->fragment_size = pa_bytes_per_second(&i->sample_spec) / 2 / i->n_fragments) <= 0) + /* Number of fragments set? */ + if (i->n_fragments < 2) { + if (i->fragment_size > 0) { + i->n_fragments = pa_bytes_per_second(&i->sample_spec) / 2 / i->fragment_size; + if (i->n_fragments < 2) + i->n_fragments = 2; + } else + i->n_fragments = 12; + } + + /* Fragment size set? */ + if (i->fragment_size <= 0) { + i->fragment_size = pa_bytes_per_second(&i->sample_spec) / 2 / i->n_fragments; + if (i->fragment_size < 1024) i->fragment_size = 1024; + } debug(__FILE__": sample spec: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); debug(__FILE__": fixated metrics to %i fragments, %li bytes each.\n", i->n_fragments, (long)i->fragment_size); -- cgit From 0f13c43797dd291b02a6b0fa1c9933a35da95c01 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 13 Jun 2006 13:21:14 +0000 Subject: Catch the access() system call as some applications do this to test if they can open /dev/dsp. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1016 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 8bad126b..da8f6786 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -101,6 +101,7 @@ static FILE* (*_fopen)(const char *path, const char *mode) = NULL; static int (*_open64)(const char *, int, mode_t) = NULL; static FILE* (*_fopen64)(const char *path, const char *mode) = NULL; static int (*_fclose)(FILE *f) = NULL; +static int (*_access)(const char *, int) = NULL; /* dlsym() violates ISO C, so confide the breakage into this function to * avoid warnings. */ @@ -141,6 +142,14 @@ do { \ pthread_mutex_unlock(&func_mutex); \ } while(0) +#define LOAD_ACCESS_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_access) \ + _access = (int (*)(const char*, int)) dlsym_fn(RTLD_NEXT, "access"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + #define LOAD_FOPEN_FUNC() \ do { \ pthread_mutex_lock(&func_mutex); \ @@ -1725,6 +1734,25 @@ int close(int fd) { return 0; } +int access(const char *pathname, int mode) { + debug(__FILE__": access()\n"); + + if (strcmp(pathname, "/dev/dsp") != 0 && + strcmp(pathname, "/dev/adsp") != 0 && + strcmp(pathname, "/dev/sndstat") != 0 && + strcmp(pathname, "/dev/mixer") != 0) { + LOAD_ACCESS_FUNC(); + return _access(pathname, mode); + } + + if (mode & (W_OK | X_OK)) { + errno = EACCES; + return -1; + } + + return 0; +} + int open64(const char *filename, int flags, ...) { va_list args; mode_t mode = 0; -- cgit From 3fa491dc905edb8f54b10bff0b896e8ad7f733c6 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 15 Jun 2006 14:47:14 +0000 Subject: Make debug output in padsp a bit less verbose. Specifying -d twice will give original output. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1018 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 258 +++++++++++++++++++++++++++++------------------------- 1 file changed, 141 insertions(+), 117 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index da8f6786..4fe8205e 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -176,7 +176,7 @@ do { \ #define CONTEXT_CHECK_DEAD_GOTO(i, label) do { \ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \ - debug(__FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ + debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ } while(0); @@ -184,20 +184,34 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \ #define STREAM_CHECK_DEAD_GOTO(i, label) do { \ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ !(i)->stream || pa_stream_get_state((i)->stream) != PA_STREAM_READY) { \ - debug(__FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ + debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ } while(0); -static void debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +static void debug(int level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); -static void debug(const char *format, ...) { +#define DEBUG_LEVEL_ALWAYS 0 +#define DEBUG_LEVEL_NORMAL 1 +#define DEBUG_LEVEL_VERBOSE 2 + +static void debug(int level, const char *format, ...) { va_list ap; - if (getenv("PADSP_DEBUG")) { - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); - } + const char *dlevel_s; + int dlevel; + + dlevel_s = getenv("PADSP_DEBUG"); + if (!dlevel_s) + return; + + dlevel = atoi(dlevel_s); + + if (dlevel < level) + return; + + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); } static int padsp_disabled(void) { @@ -280,7 +294,7 @@ static void function_exit(void) { static void fd_info_free(fd_info *i) { assert(i); - debug(__FILE__": freeing fd info (fd=%i)\n", i->app_fd); + debug(DEBUG_LEVEL_NORMAL, __FILE__": freeing fd info (fd=%i)\n", i->app_fd); dsp_drain(i); @@ -323,7 +337,7 @@ static fd_info *fd_info_ref(fd_info *i) { assert(i->ref >= 1); i->ref++; -/* debug(__FILE__": ref++, now %i\n", i->ref); */ + debug(DEBUG_LEVEL_VERBOSE, __FILE__": ref++, now %i\n", i->ref); pthread_mutex_unlock(&i->mutex); return i; @@ -334,7 +348,7 @@ static void fd_info_unref(fd_info *i) { pthread_mutex_lock(&i->mutex); assert(i->ref >= 1); r = --i->ref; -/* debug(__FILE__": ref--, now %i\n", i->ref); */ + debug(DEBUG_LEVEL_VERBOSE, __FILE__": ref--, now %i\n", i->ref); pthread_mutex_unlock(&i->mutex); if (r <= 0) @@ -397,7 +411,7 @@ static const char *stream_name(void) { static void atfork_prepare(void) { fd_info *i; - debug(__FILE__": atfork_prepare() enter\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_prepare() enter\n"); function_enter(); @@ -411,13 +425,13 @@ static void atfork_prepare(void) { pthread_mutex_lock(&func_mutex); - debug(__FILE__": atfork_prepare() exit\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_prepare() exit\n"); } static void atfork_parent(void) { fd_info *i; - debug(__FILE__": atfork_parent() enter\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_parent() enter\n"); pthread_mutex_unlock(&func_mutex); @@ -430,13 +444,13 @@ static void atfork_parent(void) { function_exit(); - debug(__FILE__": atfork_parent() exit\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_parent() exit\n"); } static void atfork_child(void) { fd_info *i; - debug(__FILE__": atfork_child() enter\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_child() enter\n"); /* We do only the bare minimum to get all fds closed */ pthread_mutex_init(&func_mutex, NULL); @@ -471,7 +485,7 @@ static void atfork_child(void) { function_exit(); - debug(__FILE__": atfork_child() exit\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_child() exit\n"); } static void install_atfork(void) { @@ -504,7 +518,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { char name[64]; static pthread_once_t install_atfork_once = PTHREAD_ONCE_INIT; - debug(__FILE__": fd_info_new()\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": fd_info_new()\n"); signal(SIGPIPE, SIG_IGN); /* Yes, ugly as hell */ @@ -535,7 +549,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfds) < 0) { *_errno = errno; - debug(__FILE__": socket() failed: %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": socket() failed: %s\n", strerror(errno)); goto fail; } @@ -544,13 +558,13 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { if (!(i->mainloop = pa_threaded_mainloop_new())) { *_errno = EIO; - debug(__FILE__": pa_threaded_mainloop_new() failed\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_threaded_mainloop_new() failed\n"); goto fail; } if (!(i->context = pa_context_new(pa_threaded_mainloop_get_api(i->mainloop), client_name(name, sizeof(name))))) { *_errno = EIO; - debug(__FILE__": pa_context_new() failed\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_context_new() failed\n"); goto fail; } @@ -558,7 +572,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { if (pa_context_connect(i->context, NULL, 0, NULL) < 0) { *_errno = ECONNREFUSED; - debug(__FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -566,7 +580,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { if (pa_threaded_mainloop_start(i->mainloop) < 0) { *_errno = EIO; - debug(__FILE__": pa_threaded_mainloop_start() failed\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_threaded_mainloop_start() failed\n"); goto unlock_and_fail; } @@ -575,7 +589,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { if (pa_context_get_state(i->context) != PA_CONTEXT_READY) { *_errno = ECONNREFUSED; - debug(__FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto unlock_and_fail; } @@ -654,8 +668,8 @@ static void fix_metrics(fd_info *i) { i->fragment_size = 1024; } - debug(__FILE__": sample spec: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); - debug(__FILE__": fixated metrics to %i fragments, %li bytes each.\n", i->n_fragments, (long)i->fragment_size); + debug(DEBUG_LEVEL_NORMAL, __FILE__": sample spec: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": fixated metrics to %i fragments, %li bytes each.\n", i->n_fragments, (long)i->fragment_size); } static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { @@ -699,7 +713,7 @@ static int fd_info_copy_data(fd_info *i, int force) { return -1; if ((n = pa_stream_writable_size(i->stream)) == (size_t) -1) { - debug(__FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); return -1; } @@ -708,7 +722,7 @@ static int fd_info_copy_data(fd_info *i, int force) { if (!i->buf) { if (!(i->buf = malloc(i->fragment_size))) { - debug(__FILE__": malloc() failed.\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": malloc() failed.\n"); return -1; } } @@ -718,12 +732,12 @@ static int fd_info_copy_data(fd_info *i, int force) { if (errno == EAGAIN) break; - debug(__FILE__": read(): %s\n", r == 0 ? "EOF" : strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": read(): %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } if (pa_stream_write(i->stream, i->buf, r, free, 0, PA_SEEK_RELATIVE) < 0) { - debug(__FILE__": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i->context))); return -1; } @@ -749,11 +763,11 @@ static void stream_state_cb(pa_stream *s, void * userdata) { switch (pa_stream_get_state(s)) { case PA_STREAM_READY: - debug(__FILE__": stream established.\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": stream established.\n"); break; case PA_STREAM_FAILED: - debug(__FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); fd_info_shutdown(i); break; @@ -773,7 +787,7 @@ static int create_stream(fd_info *i) { fix_metrics(i); if (!(i->stream = pa_stream_new(i->context, stream_name(), &i->sample_spec, NULL))) { - debug(__FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -788,7 +802,7 @@ static int create_stream(fd_info *i) { attr.minreq = i->fragment_size; if (pa_stream_connect_playback(i->stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) { - debug(__FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -847,7 +861,10 @@ static int dsp_open(int flags, int *_errno) { int ret; int f; + debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open()\n"); + if ((flags != O_WRONLY) && (flags != (O_WRONLY|O_NONBLOCK))) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": bad access flags: %x\n", flags); *_errno = EACCES; return -1; } @@ -875,7 +892,7 @@ static int dsp_open(int flags, int *_errno) { pa_threaded_mainloop_unlock(i->mainloop); - debug(__FILE__": dsp_open() succeeded, fd=%i\n", i->app_fd); + debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open() succeeded, fd=%i\n", i->app_fd); fd_info_add_to_list(i); ret = i->app_fd; @@ -891,7 +908,7 @@ fail: *_errno = EIO; - debug(__FILE__": dsp_open() failed\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open() failed\n"); return -1; } @@ -929,7 +946,7 @@ static void subscribe_cb(pa_context *context, pa_subscription_event_type_t t, ui return; if (!(o = pa_context_get_sink_info_by_index(i->context, i->sink_index, sink_info_cb, i))) { - debug(__FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); return; } @@ -941,6 +958,8 @@ static int mixer_open(int flags, int *_errno) { pa_operation *o; int ret; + debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open()\n"); + if (!(i = fd_info_new(FD_INFO_MIXER, _errno))) return -1; @@ -949,7 +968,7 @@ static int mixer_open(int flags, int *_errno) { pa_context_set_subscribe_callback(i->context, subscribe_cb, i); if (!(o = pa_context_subscribe(i->context, PA_SUBSCRIPTION_MASK_SINK, context_success_cb, i))) { - debug(__FILE__": Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; goto fail; } @@ -961,7 +980,7 @@ static int mixer_open(int flags, int *_errno) { } if (!i->operation_success) { - debug(__FILE__":Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__":Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; goto fail; } @@ -970,7 +989,7 @@ static int mixer_open(int flags, int *_errno) { pa_operation_unref(o); if (!(o = pa_context_get_sink_info_by_name(i->context, NULL, sink_info_cb, i))) { - debug(__FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; goto fail; } @@ -982,14 +1001,14 @@ static int mixer_open(int flags, int *_errno) { } if (!i->operation_success) { - debug(__FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; goto fail; } pa_threaded_mainloop_unlock(i->mainloop); - debug(__FILE__": mixer_open() succeeded, fd=%i\n", i->app_fd); + debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open() succeeded, fd=%i\n", i->app_fd); fd_info_add_to_list(i); ret = i->app_fd; @@ -1005,7 +1024,7 @@ fail: *_errno = EIO; - debug(__FILE__": mixer_open() failed\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open() failed\n"); return -1; } @@ -1039,11 +1058,11 @@ static int sndstat_open(int flags, int *_errno) { int fd = -1; int e; - debug(__FILE__": sndstat_open()\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": sndstat_open()\n"); if (flags != O_RDONLY && flags != (O_RDONLY|O_LARGEFILE)) { *_errno = EACCES; - debug(__FILE__": bad access!\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": bad access!\n"); goto fail; } @@ -1054,7 +1073,7 @@ static int sndstat_open(int flags, int *_errno) { if (fd < 0) { *_errno = e; - debug(__FILE__": mkstemp() failed: %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": mkstemp() failed: %s\n", strerror(errno)); goto fail; } @@ -1062,13 +1081,13 @@ static int sndstat_open(int flags, int *_errno) { if (write(fd, sndstat, sizeof(sndstat) -1) != sizeof(sndstat)-1) { *_errno = errno; - debug(__FILE__": write() failed: %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": write() failed: %s\n", strerror(errno)); goto fail; } if (lseek(fd, SEEK_SET, 0) < 0) { *_errno = errno; - debug(__FILE__": lseek() failed: %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": lseek() failed: %s\n", strerror(errno)); goto fail; } @@ -1085,7 +1104,7 @@ int open(const char *filename, int flags, ...) { mode_t mode = 0; int r, _errno = 0; - debug(__FILE__": open(%s)\n", filename); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": open(%s)\n", filename); va_start(args, flags); if (flags & O_CREAT) @@ -1122,19 +1141,19 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno switch (request) { case SOUND_MIXER_READ_DEVMASK : - debug(__FILE__": SOUND_MIXER_READ_DEVMASK\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_DEVMASK\n"); *(int*) argp = SOUND_MASK_PCM; break; case SOUND_MIXER_READ_RECMASK : - debug(__FILE__": SOUND_MIXER_READ_RECMASK\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_RECMASK\n"); *(int*) argp = 0; break; case SOUND_MIXER_READ_STEREODEVS: - debug(__FILE__": SOUND_MIXER_READ_STEREODEVS\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_STEREODEVS\n"); pa_threaded_mainloop_lock(i->mainloop); *(int*) argp = i->volume.channels > 1 ? SOUND_MASK_PCM : 0; @@ -1143,20 +1162,20 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno break; case SOUND_MIXER_READ_RECSRC: - debug(__FILE__": SOUND_MIXER_READ_RECSRC\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_RECSRC\n"); *(int*) argp = 0; break; case SOUND_MIXER_READ_CAPS: - debug(__FILE__": SOUND_MIXER_READ_CAPS\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_CAPS\n"); *(int*) argp = 0; break; case SOUND_MIXER_READ_PCM: - debug(__FILE__": SOUND_MIXER_READ_PCM\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_PCM\n"); pa_threaded_mainloop_lock(i->mainloop); @@ -1171,7 +1190,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno case SOUND_MIXER_WRITE_PCM: { pa_cvolume v; - debug(__FILE__": SOUND_MIXER_WRITE_PCM\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_PCM\n"); pa_threaded_mainloop_lock(i->mainloop); @@ -1184,7 +1203,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno pa_operation *o; if (!(o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, &i->volume, NULL, NULL))) - debug(__FILE__":Failed set volume: %s", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__":Failed set volume: %s", pa_strerror(pa_context_errno(i->context))); else { i->operation_success = 0; @@ -1196,7 +1215,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno exit_loop: if (!i->operation_success) - debug(__FILE__": Failed to set volume: %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to set volume: %s\n", pa_strerror(pa_context_errno(i->context))); pa_operation_unref(o); } @@ -1213,6 +1232,8 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno case SOUND_MIXER_INFO: { mixer_info *mi = argp; + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_INFO\n"); + memset(mi, 0, sizeof(mixer_info)); strncpy(mi->id, "POLYPAUDIO", sizeof(mi->id)); strncpy(mi->name, "Polypaudio Virtual OSS", sizeof(mi->name)); @@ -1223,7 +1244,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno } default: - debug(__FILE__": unknown ioctl 0x%08lx\n", request); + debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); *_errno = EINVAL; goto fail; @@ -1296,7 +1317,7 @@ static int dsp_flush_socket(fd_info *i) { return -1; if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { - debug(__FILE__": SIOCINQ: %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ: %s\n", strerror(errno)); return -1; } @@ -1306,7 +1327,7 @@ static int dsp_flush_socket(fd_info *i) { k = (size_t) l > sizeof(buf) ? sizeof(buf) : (size_t) l; if (read(i->thread_fd, buf, k) < 0) - debug(__FILE__": read(): %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": read(): %s\n", strerror(errno)); l -= k; } @@ -1324,7 +1345,7 @@ static int dsp_empty_socket(fd_info *i) { break; if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { - debug(__FILE__": SIOCINQ: %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ: %s\n", strerror(errno)); break; } @@ -1346,7 +1367,7 @@ static int dsp_drain(fd_info *i) { if (!i->mainloop) return 0; - debug(__FILE__": Draining.\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": Draining.\n"); pa_threaded_mainloop_lock(i->mainloop); @@ -1356,10 +1377,10 @@ static int dsp_drain(fd_info *i) { if (!i->stream) goto fail; - debug(__FILE__": Really draining.\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": Really draining.\n"); if (!(o = pa_stream_drain(i->stream, stream_success_cb, i))) { - debug(__FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -1371,7 +1392,7 @@ static int dsp_drain(fd_info *i) { } if (!i->operation_success) { - debug(__FILE__": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -1399,10 +1420,10 @@ static int dsp_trigger(fd_info *i) { if (dsp_empty_socket(i) < 0) goto fail; - debug(__FILE__": Triggering.\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": Triggering.\n"); if (!(o = pa_stream_trigger(i->stream, stream_success_cb, i))) { - debug(__FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -1414,7 +1435,7 @@ static int dsp_trigger(fd_info *i) { } if (!i->operation_success) { - debug(__FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -1435,7 +1456,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) switch (request) { case SNDCTL_DSP_SETFMT: { - debug(__FILE__": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp); pa_threaded_mainloop_lock(i->mainloop); @@ -1455,7 +1476,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) int valid; char t[256]; - debug(__FILE__": SNDCTL_DSP_SPEED: %i\n", *(int*) argp); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SPEED: %i\n", *(int*) argp); pa_threaded_mainloop_lock(i->mainloop); @@ -1467,7 +1488,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) free_stream(i); } - debug(__FILE__": ss: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": ss: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); pa_threaded_mainloop_unlock(i->mainloop); @@ -1480,7 +1501,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) } case SNDCTL_DSP_STEREO: - debug(__FILE__": SNDCTL_DSP_STEREO: %i\n", *(int*) argp); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_STEREO: %i\n", *(int*) argp); pa_threaded_mainloop_lock(i->mainloop); @@ -1494,7 +1515,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_sample_spec ss; int valid; - debug(__FILE__": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp); pa_threaded_mainloop_lock(i->mainloop); @@ -1517,7 +1538,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) } case SNDCTL_DSP_GETBLKSIZE: - debug(__FILE__": SNDCTL_DSP_GETBLKSIZE\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETBLKSIZE\n"); pa_threaded_mainloop_lock(i->mainloop); @@ -1529,7 +1550,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) break; case SNDCTL_DSP_SETFRAGMENT: - debug(__FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%8x\n", *(int*) argp); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%8x\n", *(int*) argp); pa_threaded_mainloop_lock(i->mainloop); @@ -1543,7 +1564,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) break; case SNDCTL_DSP_GETCAPS: - debug(__FILE__": SNDCTL_DSP_CAPS\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CAPS\n"); *(int*) argp = DSP_CAP_MULTI; break; @@ -1551,7 +1572,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_GETODELAY: { int l; - debug(__FILE__": SNDCTL_DSP_GETODELAY\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETODELAY\n"); pa_threaded_mainloop_lock(i->mainloop); @@ -1568,7 +1589,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) } if (pa_context_errno(i->context) != PA_ERR_NODATA) { - debug(__FILE__": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i->context))); break; } @@ -1578,19 +1599,19 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) exit_loop: if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) - debug(__FILE__": SIOCINQ failed: %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); else *(int*) argp += l; pa_threaded_mainloop_unlock(i->mainloop); - debug(__FILE__": ODELAY: %i\n", *(int*) argp); + debug(DEBUG_LEVEL_NORMAL, __FILE__": ODELAY: %i\n", *(int*) argp); break; } case SNDCTL_DSP_RESET: { - debug(__FILE__": SNDCTL_DSP_RESET\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_RESET\n"); pa_threaded_mainloop_lock(i->mainloop); @@ -1603,21 +1624,21 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) } case SNDCTL_DSP_GETFMTS: { - debug(__FILE__": SNDCTL_DSP_GETFMTS\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETFMTS\n"); *(int*) argp = AFMT_MU_LAW|AFMT_A_LAW|AFMT_U8|AFMT_S16_LE|AFMT_S16_BE; break; } case SNDCTL_DSP_POST: - debug(__FILE__": SNDCTL_DSP_POST\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_POST\n"); if (dsp_trigger(i) < 0) *_errno = EIO; break; case SNDCTL_DSP_SYNC: - debug(__FILE__": SNDCTL_DSP_SYNC\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SYNC\n"); if (dsp_drain(i) < 0) *_errno = EIO; @@ -1629,7 +1650,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) int l; size_t k = 0; - debug(__FILE__": SNDCTL_DSP_GETOSPACE\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETOSPACE\n"); pa_threaded_mainloop_lock(i->mainloop); @@ -1637,12 +1658,12 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) if (i->stream) { if ((k = pa_stream_writable_size(i->stream)) == (size_t) -1) - debug(__FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); } else k = i->fragment_size * i->n_fragments; if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { - debug(__FILE__": SIOCINQ failed: %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); l = 0; } @@ -1653,13 +1674,13 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_unlock(i->mainloop); - debug(__FILE__": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi->fragsize, bi->fragstotal, bi->bytes, bi->fragments); + debug(DEBUG_LEVEL_NORMAL, __FILE__": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi->fragsize, bi->fragstotal, bi->bytes, bi->fragments); break; } default: - debug(__FILE__": unknwon ioctl 0x%08lx\n", request); + debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); *_errno = EINVAL; goto fail; @@ -1678,7 +1699,7 @@ int ioctl(int fd, unsigned long request, ...) { void *argp; int r, _errno = 0; - debug(__FILE__": ioctl()\n"); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": ioctl()\n"); va_start(args, request); argp = va_arg(args, void *); @@ -1713,7 +1734,7 @@ int ioctl(int fd, unsigned long request, ...) { int close(int fd) { fd_info *i; - debug(__FILE__": close()\n"); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": close()\n"); if (!function_enter()) { LOAD_CLOSE_FUNC(); @@ -1735,7 +1756,7 @@ int close(int fd) { } int access(const char *pathname, int mode) { - debug(__FILE__": access()\n"); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": access(%s)\n", pathname); if (strcmp(pathname, "/dev/dsp") != 0 && strcmp(pathname, "/dev/adsp") != 0 && @@ -1746,10 +1767,13 @@ int access(const char *pathname, int mode) { } if (mode & (W_OK | X_OK)) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": access(%s, %x) = EACCESS\n", pathname, mode); errno = EACCES; return -1; } + debug(DEBUG_LEVEL_NORMAL, __FILE__": access(%s, %x) = OK\n", pathname, mode); + return 0; } @@ -1757,7 +1781,7 @@ int open64(const char *filename, int flags, ...) { va_list args; mode_t mode = 0; - debug(__FILE__": open64(%s)\n", filename); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": open64(%s)\n", filename); va_start(args, flags); if (flags & O_CREAT) @@ -1780,31 +1804,31 @@ FILE* fopen(const char *filename, const char *mode) { int fd; mode_t m; - debug(__FILE__": fopen(%s)\n", filename); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen(%s)\n", filename); - if (strcmp(filename, "/dev/dsp") == 0 || - strcmp(filename, "/dev/adsp") == 0) { - - if (strcmp(mode, "wb") != 0) { - errno = EACCES; - return NULL; - } + if (strcmp(filename, "/dev/dsp") != 0 && + strcmp(filename, "/dev/adsp") != 0 && + strcmp(filename, "/dev/sndstat") != 0 && + strcmp(filename, "/dev/mixer") != 0) { + LOAD_FOPEN_FUNC(); + return _fopen(filename, mode); + } + switch (mode[0]) { + case 'r': + m = O_RDONLY; + break; + case 'w': + case 'a': m = O_WRONLY; - } else if (strcmp(filename, "/dev/sndstat") == 0) { - - if (strcmp(mode, "r") != 0) { - errno = EACCES; - return NULL; - } + break; + default: + errno = EINVAL; + return NULL; + } - m = O_RDONLY; - } else if (strcmp(filename, "/dev/mixer") == 0) + if ((((mode[1] == 'b') || (mode[1] == 't')) && (mode[2] == '+')) || (mode[1] == '+')) m = O_RDWR; - else { - LOAD_FOPEN_FUNC(); - return _fopen(filename, mode); - } if ((fd = open(filename, m)) < 0) return NULL; @@ -1819,7 +1843,7 @@ FILE* fopen(const char *filename, const char *mode) { FILE *fopen64(const char *filename, const char *mode) { - debug(__FILE__": fopen64(%s)\n", filename); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen64(%s)\n", filename); if (strcmp(filename, "/dev/dsp") != 0 && strcmp(filename, "/dev/adsp") != 0 && @@ -1835,7 +1859,7 @@ FILE *fopen64(const char *filename, const char *mode) { int fclose(FILE *f) { fd_info *i; - debug(__FILE__": fclose()\n"); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": fclose()\n"); if (!function_enter()) { LOAD_FCLOSE_FUNC(); -- cgit From 6684264b69a17ec907c903c6f9ca9b99dbd29be2 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 16 Jun 2006 21:07:32 +0000 Subject: Record support. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1021 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 567 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 435 insertions(+), 132 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 4fe8205e..b0e76327 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -52,7 +52,7 @@ typedef enum { FD_INFO_MIXER, - FD_INFO_PLAYBACK + FD_INFO_STREAM, } fd_info_type_t; typedef struct fd_info fd_info; @@ -71,16 +71,18 @@ struct fd_info { pa_threaded_mainloop *mainloop; pa_context *context; - pa_stream *stream; + pa_stream *play_stream; + pa_stream *rec_stream; pa_io_event *io_event; void *buf; + size_t rec_offset; int operation_success; - pa_cvolume volume; - uint32_t sink_index; + pa_cvolume sink_volume, source_volume; + uint32_t sink_index, source_index; int volume_modify_count; PA_LLIST_FIELDS(fd_info); @@ -181,9 +183,17 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \ } \ } while(0); -#define STREAM_CHECK_DEAD_GOTO(i, label) do { \ +#define PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, label) do { \ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ - !(i)->stream || pa_stream_get_state((i)->stream) != PA_STREAM_READY) { \ + !(i)->play_stream || pa_stream_get_state((i)->play_stream) != PA_STREAM_READY) { \ + debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ + goto label; \ +} \ +} while(0); + +#define RECORD_STREAM_CHECK_DEAD_GOTO(i, label) do { \ +if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ + !(i)->rec_stream || pa_stream_get_state((i)->rec_stream) != PA_STREAM_READY) { \ debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ @@ -301,9 +311,14 @@ static void fd_info_free(fd_info *i) { if (i->mainloop) pa_threaded_mainloop_stop(i->mainloop); - if (i->stream) { - pa_stream_disconnect(i->stream); - pa_stream_unref(i->stream); + if (i->play_stream) { + pa_stream_disconnect(i->play_stream); + pa_stream_unref(i->play_stream); + } + + if (i->rec_stream) { + pa_stream_disconnect(i->rec_stream); + pa_stream_unref(i->rec_stream); } if (i->context) { @@ -465,9 +480,14 @@ static void atfork_child(void) { i->context = NULL; } - if (i->stream) { - pa_stream_unref(i->stream); - i->stream = NULL; + if (i->play_stream) { + pa_stream_unref(i->play_stream); + i->play_stream = NULL; + } + + if (i->rec_stream) { + pa_stream_unref(i->rec_stream); + i->rec_stream = NULL; } if (i->app_fd >= 0) { @@ -534,15 +554,19 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { i->mainloop = NULL; i->context = NULL; - i->stream = NULL; + i->play_stream = NULL; + i->rec_stream = NULL; i->io_event = NULL; pthread_mutex_init(&i->mutex, NULL); i->ref = 1; i->buf = NULL; + i->rec_offset = 0; i->unusable = 0; - pa_cvolume_reset(&i->volume, 2); + pa_cvolume_reset(&i->sink_volume, 2); + pa_cvolume_reset(&i->source_volume, 2); i->volume_modify_count = 0; i->sink_index = (uint32_t) -1; + i->source_index = (uint32_t) -1; PA_LLIST_INIT(fd_info, i); reset_params(i); @@ -678,8 +702,36 @@ static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { if (i->io_event) { pa_mainloop_api *api; + pa_io_event_flags_t flags; + size_t n; + api = pa_threaded_mainloop_get_api(i->mainloop); - api->io_enable(i->io_event, PA_IO_EVENT_INPUT); + + flags = 0; + + if (s == i->play_stream) { + n = pa_stream_writable_size(i->play_stream); + if (n == (size_t)-1) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", + pa_strerror(pa_context_errno(i->context))); + } + + if (n >= i->fragment_size) + flags |= PA_IO_EVENT_INPUT; + } + + if (s == i->rec_stream) { + n = pa_stream_readable_size(i->rec_stream); + if (n == (size_t)-1) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_readable_size(): %s\n", + pa_strerror(pa_context_errno(i->context))); + } + + if (n >= i->fragment_size) + flags |= PA_IO_EVENT_OUTPUT; + } + + api->io_enable(i->io_event, flags); } } @@ -708,49 +760,114 @@ static void fd_info_shutdown(fd_info *i) { static int fd_info_copy_data(fd_info *i, int force) { size_t n; + pa_io_event_flags_t flags; - if (!i->stream) + if (!i->play_stream && !i->rec_stream) return -1; - if ((n = pa_stream_writable_size(i->stream)) == (size_t) -1) { - debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); - return -1; - } - - while (n >= i->fragment_size || force) { - ssize_t r; - - if (!i->buf) { - if (!(i->buf = malloc(i->fragment_size))) { - debug(DEBUG_LEVEL_NORMAL, __FILE__": malloc() failed.\n"); + flags = 0; + + if (i->play_stream) { + n = pa_stream_writable_size(i->play_stream); + + if (n == (size_t)-1) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", + pa_strerror(pa_context_errno(i->context))); + return -1; + } + + while (n >= i->fragment_size || force) { + ssize_t r; + + if (!i->buf) { + if (!(i->buf = malloc(i->fragment_size))) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": malloc() failed.\n"); + return -1; + } + } + + if ((r = read(i->thread_fd, i->buf, i->fragment_size)) <= 0) { + + if (errno == EAGAIN) + break; + + debug(DEBUG_LEVEL_NORMAL, __FILE__": read(): %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } - } - - if ((r = read(i->thread_fd, i->buf, i->fragment_size)) <= 0) { - if (errno == EAGAIN) - break; - - debug(DEBUG_LEVEL_NORMAL, __FILE__": read(): %s\n", r == 0 ? "EOF" : strerror(errno)); - return -1; + if (pa_stream_write(i->play_stream, i->buf, r, free, 0, PA_SEEK_RELATIVE) < 0) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i->context))); + return -1; + } + + i->buf = NULL; + + assert(n >= (size_t) r); + n -= r; } - - if (pa_stream_write(i->stream, i->buf, r, free, 0, PA_SEEK_RELATIVE) < 0) { - debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i->context))); + + if (n >= i->fragment_size) + flags |= PA_IO_EVENT_INPUT; + } + + if (i->rec_stream) { + n = pa_stream_readable_size(i->rec_stream); + + if (n == (size_t)-1) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_readable_size(): %s\n", + pa_strerror(pa_context_errno(i->context))); return -1; } - i->buf = NULL; + while (n >= i->fragment_size || force) { + ssize_t r; + const void *data; + const char *buf; + size_t len; + + if (pa_stream_peek(i->rec_stream, &data, &len) < 0) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_peek(): %s\n", pa_strerror(pa_context_errno(i->context))); + return -1; + } + + if (!data) + break; - assert(n >= (size_t) r); - n -= r; + buf = (const char*)data + i->rec_offset; + + if ((r = write(i->thread_fd, buf, len - i->rec_offset)) <= 0) { + + if (errno == EAGAIN) + break; + + debug(DEBUG_LEVEL_NORMAL, __FILE__": write(): %s\n", strerror(errno)); + return -1; + } + + assert((size_t)r <= len - i->rec_offset); + i->rec_offset += r; + + if (i->rec_offset == len) { + if (pa_stream_drop(i->rec_stream) < 0) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drop(): %s\n", pa_strerror(pa_context_errno(i->context))); + return -1; + } + i->rec_offset = 0; + } + + assert(n >= (size_t) r); + n -= r; + } + + if (n >= i->fragment_size) + flags |= PA_IO_EVENT_OUTPUT; } if (i->io_event) { pa_mainloop_api *api; + api = pa_threaded_mainloop_get_api(i->mainloop); - api->io_enable(i->io_event, n >= i->fragment_size ? PA_IO_EVENT_INPUT : 0); + api->io_enable(i->io_event, flags); } return 0; @@ -778,7 +895,7 @@ static void stream_state_cb(pa_stream *s, void * userdata) { } } -static int create_stream(fd_info *i) { +static int create_playback_stream(fd_info *i) { pa_buffer_attr attr; int n; @@ -786,14 +903,14 @@ static int create_stream(fd_info *i) { fix_metrics(i); - if (!(i->stream = pa_stream_new(i->context, stream_name(), &i->sample_spec, NULL))) { + if (!(i->play_stream = pa_stream_new(i->context, stream_name(), &i->sample_spec, NULL))) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } - pa_stream_set_state_callback(i->stream, stream_state_cb, i); - pa_stream_set_write_callback(i->stream, stream_request_cb, i); - pa_stream_set_latency_update_callback(i->stream, stream_latency_update_cb, i); + pa_stream_set_state_callback(i->play_stream, stream_state_cb, i); + pa_stream_set_write_callback(i->play_stream, stream_request_cb, i); + pa_stream_set_latency_update_callback(i->play_stream, stream_latency_update_cb, i); memset(&attr, 0, sizeof(attr)); attr.maxlength = i->fragment_size * (i->n_fragments+1); @@ -801,7 +918,7 @@ static int create_stream(fd_info *i) { attr.prebuf = i->fragment_size; attr.minreq = i->fragment_size; - if (pa_stream_connect_playback(i->stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) { + if (pa_stream_connect_playback(i->play_stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -817,13 +934,56 @@ fail: return -1; } -static void free_stream(fd_info *i) { +static int create_record_stream(fd_info *i) { + pa_buffer_attr attr; + int n; + assert(i); - if (i->stream) { - pa_stream_disconnect(i->stream); - pa_stream_unref(i->stream); - i->stream = NULL; + fix_metrics(i); + + if (!(i->rec_stream = pa_stream_new(i->context, stream_name(), &i->sample_spec, NULL))) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + pa_stream_set_state_callback(i->rec_stream, stream_state_cb, i); + pa_stream_set_read_callback(i->rec_stream, stream_request_cb, i); + pa_stream_set_latency_update_callback(i->rec_stream, stream_latency_update_cb, i); + + memset(&attr, 0, sizeof(attr)); + attr.maxlength = i->fragment_size * (i->n_fragments+1); + attr.fragsize = i->fragment_size; + + if (pa_stream_connect_record(i->rec_stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE) < 0) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + n = i->fragment_size; + setsockopt(i->app_fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)); + n = i->fragment_size; + setsockopt(i->thread_fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)); + + return 0; + +fail: + return -1; +} + +static void free_streams(fd_info *i) { + assert(i); + + if (i->play_stream) { + pa_stream_disconnect(i->play_stream); + pa_stream_unref(i->play_stream); + i->play_stream = NULL; + } + + if (i->rec_stream) { + pa_stream_disconnect(i->rec_stream); + pa_stream_unref(i->rec_stream); + i->rec_stream = NULL; } } @@ -834,17 +994,24 @@ static void io_event_cb(pa_mainloop_api *api, pa_io_event *e, int fd, pa_io_even if (flags & PA_IO_EVENT_INPUT) { - if (!i->stream) { - api->io_enable(e, 0); - - if (create_stream(i) < 0) + if (!i->play_stream) { + if (create_playback_stream(i) < 0) goto fail; - } else { if (fd_info_copy_data(i, 0) < 0) goto fail; } + } else if (flags & PA_IO_EVENT_OUTPUT) { + + if (!i->rec_stream) { + if (create_record_stream(i) < 0) + goto fail; + } else { + if (fd_info_copy_data(i, 0) < 0) + goto fail; + } + } else if (flags & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) goto fail; @@ -860,21 +1027,13 @@ static int dsp_open(int flags, int *_errno) { pa_mainloop_api *api; int ret; int f; + pa_io_event_flags_t ioflags; debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open()\n"); - if ((flags != O_WRONLY) && (flags != (O_WRONLY|O_NONBLOCK))) { - debug(DEBUG_LEVEL_NORMAL, __FILE__": bad access flags: %x\n", flags); - *_errno = EACCES; - return -1; - } - - if (!(i = fd_info_new(FD_INFO_PLAYBACK, _errno))) + if (!(i = fd_info_new(FD_INFO_STREAM, _errno))) return -1; - shutdown(i->thread_fd, SHUT_WR); - shutdown(i->app_fd, SHUT_RD); - if ((flags & O_NONBLOCK) == O_NONBLOCK) { if ((f = fcntl(i->app_fd, F_GETFL)) >= 0) fcntl(i->app_fd, F_SETFL, f|O_NONBLOCK); @@ -887,7 +1046,26 @@ static int dsp_open(int flags, int *_errno) { pa_threaded_mainloop_lock(i->mainloop); api = pa_threaded_mainloop_get_api(i->mainloop); - if (!(i->io_event = api->io_new(api, i->thread_fd, PA_IO_EVENT_INPUT, io_event_cb, i))) + + switch (flags & O_ACCMODE) { + case O_RDONLY: + ioflags = PA_IO_EVENT_OUTPUT; + shutdown(i->thread_fd, SHUT_RD); + shutdown(i->app_fd, SHUT_WR); + break; + case O_WRONLY: + ioflags = PA_IO_EVENT_INPUT; + shutdown(i->thread_fd, SHUT_WR); + shutdown(i->app_fd, SHUT_RD); + break; + case O_RDWR: + ioflags = PA_IO_EVENT_INPUT | PA_IO_EVENT_OUTPUT; + break; + default: + return -1; + } + + if (!(i->io_event = api->io_new(api, i->thread_fd, ioflags, io_event_cb, i))) goto fail; pa_threaded_mainloop_unlock(i->mainloop); @@ -925,16 +1103,38 @@ static void sink_info_cb(pa_context *context, const pa_sink_info *si, int eol, v if (eol) return; - if (!pa_cvolume_equal(&i->volume, &si->volume)) + if (!pa_cvolume_equal(&i->sink_volume, &si->volume)) i->volume_modify_count++; - i->volume = si->volume; + i->sink_volume = si->volume; i->sink_index = si->index; i->operation_success = 1; pa_threaded_mainloop_signal(i->mainloop, 0); } +static void source_info_cb(pa_context *context, const pa_source_info *si, int eol, void *userdata) { + fd_info *i = userdata; + + if (!si && eol < 0) { + i->operation_success = 0; + pa_threaded_mainloop_signal(i->mainloop, 0); + return; + } + + if (eol) + return; + + if (!pa_cvolume_equal(&i->source_volume, &si->volume)) + i->volume_modify_count++; + + i->source_volume = si->volume; + i->source_index = si->index; + + i->operation_success = 1; + pa_threaded_mainloop_signal(i->mainloop, 0); +} + static void subscribe_cb(pa_context *context, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { fd_info *i = userdata; pa_operation *o = NULL; @@ -955,7 +1155,7 @@ static void subscribe_cb(pa_context *context, pa_subscription_event_type_t t, ui static int mixer_open(int flags, int *_errno) { fd_info *i; - pa_operation *o; + pa_operation *o = NULL; int ret; debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open()\n"); @@ -967,7 +1167,7 @@ static int mixer_open(int flags, int *_errno) { pa_context_set_subscribe_callback(i->context, subscribe_cb, i); - if (!(o = pa_context_subscribe(i->context, PA_SUBSCRIPTION_MASK_SINK, context_success_cb, i))) { + if (!(o = pa_context_subscribe(i->context, PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE, context_success_cb, i))) { debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; goto fail; @@ -979,6 +1179,9 @@ static int mixer_open(int flags, int *_errno) { CONTEXT_CHECK_DEAD_GOTO(i, fail); } + pa_operation_unref(o); + o = NULL; + if (!i->operation_success) { debug(DEBUG_LEVEL_NORMAL, __FILE__":Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; @@ -987,7 +1190,6 @@ static int mixer_open(int flags, int *_errno) { /* Get sink info */ - pa_operation_unref(o); if (!(o = pa_context_get_sink_info_by_name(i->context, NULL, sink_info_cb, i))) { debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; @@ -1000,12 +1202,38 @@ static int mixer_open(int flags, int *_errno) { CONTEXT_CHECK_DEAD_GOTO(i, fail); } + pa_operation_unref(o); + o = NULL; + if (!i->operation_success) { debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; goto fail; } + /* Get source info */ + + if (!(o = pa_context_get_source_info_by_name(i->context, NULL, source_info_cb, i))) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get source info: %s", pa_strerror(pa_context_errno(i->context))); + *_errno = EIO; + goto fail; + } + + i->operation_success = 0; + while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(i->mainloop); + CONTEXT_CHECK_DEAD_GOTO(i, fail); + } + + pa_operation_unref(o); + o = NULL; + + if (!i->operation_success) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get source info: %s", pa_strerror(pa_context_errno(i->context))); + *_errno = EIO; + goto fail; + } + pa_threaded_mainloop_unlock(i->mainloop); debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open() succeeded, fd=%i\n", i->app_fd); @@ -1017,6 +1245,9 @@ static int mixer_open(int flags, int *_errno) { return ret; fail: + if (o) + pa_operation_unref(o); + pa_threaded_mainloop_unlock(i->mainloop); if (i) @@ -1143,20 +1374,24 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno case SOUND_MIXER_READ_DEVMASK : debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_DEVMASK\n"); - *(int*) argp = SOUND_MASK_PCM; + *(int*) argp = SOUND_MASK_PCM | SOUND_MASK_IGAIN; break; case SOUND_MIXER_READ_RECMASK : debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_RECMASK\n"); - *(int*) argp = 0; + *(int*) argp = SOUND_MASK_IGAIN; break; case SOUND_MIXER_READ_STEREODEVS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_STEREODEVS\n"); pa_threaded_mainloop_lock(i->mainloop); - *(int*) argp = i->volume.channels > 1 ? SOUND_MASK_PCM : 0; + *(int*) argp = 0; + if (i->sink_volume.channels > 1) + *(int*) argp |= SOUND_MASK_PCM; + if (i->source_volume.channels > 1) + *(int*) argp |= SOUND_MASK_IGAIN; pa_threaded_mainloop_unlock(i->mainloop); break; @@ -1164,9 +1399,13 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno case SOUND_MIXER_READ_RECSRC: debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_RECSRC\n"); - *(int*) argp = 0; + *(int*) argp = SOUND_MASK_IGAIN; break; - + + case SOUND_MIXER_WRITE_RECSRC: + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_RECSRC\n"); + break; + case SOUND_MIXER_READ_CAPS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_CAPS\n"); @@ -1174,35 +1413,61 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno break; case SOUND_MIXER_READ_PCM: - - debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_PCM\n"); - + case SOUND_MIXER_READ_IGAIN: { + pa_cvolume *v; + + if (request == SOUND_MIXER_READ_PCM) + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_PCM\n"); + else + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_IGAIN\n"); + pa_threaded_mainloop_lock(i->mainloop); + if (request == SOUND_MIXER_READ_PCM) + v = &i->sink_volume; + else + v = &i->source_volume; + *(int*) argp = - ((i->volume.values[0]*100/PA_VOLUME_NORM)) | - ((i->volume.values[i->volume.channels > 1 ? 1 : 0]*100/PA_VOLUME_NORM) << 8); - + ((v->values[0]*100/PA_VOLUME_NORM)) | + ((v->values[v->channels > 1 ? 1 : 0]*100/PA_VOLUME_NORM) << 8); + pa_threaded_mainloop_unlock(i->mainloop); - + break; + } + + case SOUND_MIXER_WRITE_PCM: + case SOUND_MIXER_WRITE_IGAIN: { + pa_cvolume v, *pv; + + if (request == SOUND_MIXER_READ_PCM) + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_PCM\n"); + else + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_IGAIN\n"); - case SOUND_MIXER_WRITE_PCM: { - pa_cvolume v; - - debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_PCM\n"); - pa_threaded_mainloop_lock(i->mainloop); - v = i->volume; - - i->volume.values[0] = ((*(int*) argp & 0xFF)*PA_VOLUME_NORM)/100; - i->volume.values[1] = ((*(int*) argp >> 8)*PA_VOLUME_NORM)/100; + if (request == SOUND_MIXER_READ_PCM) { + v = i->sink_volume; + pv = &i->sink_volume; + } else { + v = i->source_volume; + pv = &i->source_volume; + } + + pv->values[0] = ((*(int*) argp & 0xFF)*PA_VOLUME_NORM)/100; + pv->values[1] = ((*(int*) argp >> 8)*PA_VOLUME_NORM)/100; - if (!pa_cvolume_equal(&i->volume, &v)) { + if (!pa_cvolume_equal(pv, &v)) { pa_operation *o; - - if (!(o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, &i->volume, NULL, NULL))) + + if (request == SOUND_MIXER_READ_PCM) + o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, pv, NULL, NULL); + else + o = pa_context_set_source_volume_by_index(i->context, i->source_index, pv, NULL, NULL); + + if (!o) debug(DEBUG_LEVEL_NORMAL, __FILE__":Failed set volume: %s", pa_strerror(pa_context_errno(i->context))); else { @@ -1310,13 +1575,10 @@ static int map_format_back(pa_sample_format_t format) { } } -static int dsp_flush_socket(fd_info *i) { +static int dsp_flush_fd(int fd) { int l; - - if (i->thread_fd < 0) - return -1; - if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { + if (ioctl(fd, SIOCINQ, &l) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ: %s\n", strerror(errno)); return -1; } @@ -1326,7 +1588,7 @@ static int dsp_flush_socket(fd_info *i) { size_t k; k = (size_t) l > sizeof(buf) ? sizeof(buf) : (size_t) l; - if (read(i->thread_fd, buf, k) < 0) + if (read(fd, buf, k) < 0) debug(DEBUG_LEVEL_NORMAL, __FILE__": read(): %s\n", strerror(errno)); l -= k; } @@ -1334,6 +1596,27 @@ static int dsp_flush_socket(fd_info *i) { return 0; } +static int dsp_flush_socket(fd_info *i) { + int res = 0; + + if ((i->thread_fd < 0) && (i->app_fd < 0)) + return -1; + + if (i->thread_fd >= 0) + res = dsp_flush_fd(i->thread_fd); + + if (res < 0) + return res; + + if (i->app_fd >= 0) + res = dsp_flush_fd(i->app_fd); + + if (res < 0) + return res; + + return 0; +} + static int dsp_empty_socket(fd_info *i) { int ret = -1; @@ -1374,19 +1657,19 @@ static int dsp_drain(fd_info *i) { if (dsp_empty_socket(i) < 0) goto fail; - if (!i->stream) + if (!i->play_stream) goto fail; debug(DEBUG_LEVEL_NORMAL, __FILE__": Really draining.\n"); - if (!(o = pa_stream_drain(i->stream, stream_success_cb, i))) { + if (!(o = pa_stream_drain(i->play_stream, stream_success_cb, i))) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } i->operation_success = 0; while (pa_operation_get_state(o) != PA_OPERATION_DONE) { - STREAM_CHECK_DEAD_GOTO(i, fail); + PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail); pa_threaded_mainloop_wait(i->mainloop); } @@ -1412,7 +1695,7 @@ static int dsp_trigger(fd_info *i) { pa_operation *o = NULL; int r = -1; - if (!i->stream) + if (!i->play_stream) return 0; pa_threaded_mainloop_lock(i->mainloop); @@ -1422,14 +1705,14 @@ static int dsp_trigger(fd_info *i) { debug(DEBUG_LEVEL_NORMAL, __FILE__": Triggering.\n"); - if (!(o = pa_stream_trigger(i->stream, stream_success_cb, i))) { + if (!(o = pa_stream_trigger(i->play_stream, stream_success_cb, i))) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } i->operation_success = 0; while (!pa_operation_get_state(o) != PA_OPERATION_DONE) { - STREAM_CHECK_DEAD_GOTO(i, fail); + PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail); pa_threaded_mainloop_wait(i->mainloop); } @@ -1464,7 +1747,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) *(int*) argp = map_format_back(i->sample_spec.format); else { map_format((int*) argp, &i->sample_spec); - free_stream(i); + free_streams(i); } pa_threaded_mainloop_unlock(i->mainloop); @@ -1485,7 +1768,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) if ((valid = pa_sample_spec_valid(&ss))) { i->sample_spec = ss; - free_stream(i); + free_streams(i); } debug(DEBUG_LEVEL_NORMAL, __FILE__": ss: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); @@ -1506,7 +1789,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_lock(i->mainloop); i->sample_spec.channels = *(int*) argp ? 2 : 1; - free_stream(i); + free_streams(i); pa_threaded_mainloop_unlock(i->mainloop); return 0; @@ -1524,7 +1807,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) if ((valid = pa_sample_spec_valid(&ss))) { i->sample_spec = ss; - free_stream(i); + free_streams(i); } pa_threaded_mainloop_unlock(i->mainloop); @@ -1557,7 +1840,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) i->fragment_size = 1 << (*(int*) argp); i->n_fragments = (*(int*) argp) >> 16; - free_stream(i); + free_streams(i); pa_threaded_mainloop_unlock(i->mainloop); @@ -1566,7 +1849,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_GETCAPS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CAPS\n"); - *(int*) argp = DSP_CAP_MULTI; + *(int*) argp = DSP_CAP_DUPLEX | DSP_CAP_MULTI; break; case SNDCTL_DSP_GETODELAY: { @@ -1581,9 +1864,9 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) for (;;) { pa_usec_t usec; - STREAM_CHECK_DEAD_GOTO(i, exit_loop); + PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, exit_loop); - if (pa_stream_get_latency(i->stream, &usec, NULL) >= 0) { + if (pa_stream_get_latency(i->play_stream, &usec, NULL) >= 0) { *(int*) argp = pa_usec_to_bytes(usec, &i->sample_spec); break; } @@ -1615,7 +1898,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_lock(i->mainloop); - free_stream(i); + free_streams(i); dsp_flush_socket(i); reset_params(i); @@ -1645,31 +1928,51 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) break; - case SNDCTL_DSP_GETOSPACE: { + case SNDCTL_DSP_GETOSPACE: + case SNDCTL_DSP_GETISPACE: { audio_buf_info *bi = (audio_buf_info*) argp; int l; size_t k = 0; - debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETOSPACE\n"); + if (request == SNDCTL_DSP_GETOSPACE) + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETOSPACE\n"); + else + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETISPACE\n"); pa_threaded_mainloop_lock(i->mainloop); fix_metrics(i); - - if (i->stream) { - if ((k = pa_stream_writable_size(i->stream)) == (size_t) -1) - debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); - } else - k = i->fragment_size * i->n_fragments; - - if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { - debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); - l = 0; + + if (request == SNDCTL_DSP_GETOSPACE) { + if (i->play_stream) { + if ((k = pa_stream_writable_size(i->play_stream)) == (size_t) -1) + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); + } else + k = i->fragment_size * i->n_fragments; + + if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); + l = 0; + } + + bi->bytes = k > (size_t) l ? k - l : 0; + } else { + if (i->rec_stream) { + if ((k = pa_stream_readable_size(i->rec_stream)) == (size_t) -1) + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_readable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); + } else + k = 0; + + if (ioctl(i->app_fd, SIOCINQ, &l) < 0) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); + l = 0; + } + + bi->bytes = k + l; } bi->fragsize = i->fragment_size; bi->fragstotal = i->n_fragments; - bi->bytes = k > (size_t) l ? k - l : 0; bi->fragments = bi->bytes / bi->fragsize; pa_threaded_mainloop_unlock(i->mainloop); -- cgit From e66b0e6d3f235a65913c17a549bed74fd414445a Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 16 Jun 2006 21:08:35 +0000 Subject: Creating a stream might take some time, so check that it's in the right state before transferring data. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1022 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index b0e76327..be935060 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -767,7 +767,7 @@ static int fd_info_copy_data(fd_info *i, int force) { flags = 0; - if (i->play_stream) { + if ((i->play_stream) && (pa_stream_get_state(i->play_stream) == PA_STREAM_READY)) { n = pa_stream_writable_size(i->play_stream); if (n == (size_t)-1) { @@ -810,7 +810,7 @@ static int fd_info_copy_data(fd_info *i, int force) { flags |= PA_IO_EVENT_INPUT; } - if (i->rec_stream) { + if ((i->rec_stream) && (pa_stream_get_state(i->rec_stream) == PA_STREAM_READY)) { n = pa_stream_readable_size(i->rec_stream); if (n == (size_t)-1) { -- cgit From 8485a477053f7ea9549a1ca588c32b5379ba2d36 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 16 Jun 2006 21:11:45 +0000 Subject: /dev/dsp should default to U8, not mulaw. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1023 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index be935060..e25fdfd8 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -392,7 +392,7 @@ static void context_state_cb(pa_context *c, void *userdata) { static void reset_params(fd_info *i) { assert(i); - i->sample_spec.format = PA_SAMPLE_ULAW; + i->sample_spec.format = PA_SAMPLE_U8; i->sample_spec.channels = 1; i->sample_spec.rate = 8000; i->fragment_size = 0; -- cgit From c6d4cc0af9497a4376fa1dcb33a28c9a54264109 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 19 Jun 2006 16:39:28 +0000 Subject: Handle clients that just want to set fragment size (and not count). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1030 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index e25fdfd8..56acbb28 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1839,7 +1839,11 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) i->fragment_size = 1 << (*(int*) argp); i->n_fragments = (*(int*) argp) >> 16; - + + /* 0x7FFF means that we can set whatever we like */ + if (i->n_fragments == 0x7FFF) + i->n_fragments = 12; + free_streams(i); pa_threaded_mainloop_unlock(i->mainloop); -- cgit From f44ba092651aa75055e109e04b4164ea92ae7fdc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 21:53:48 +0000 Subject: big s/polyp/pulse/g git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1033 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 56acbb28..13f571e1 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -46,9 +46,9 @@ #include -#include -#include -#include +#include +#include +#include typedef enum { FD_INFO_MIXER, -- cgit From 10b5e997d7a8a4e955ce49cc816fdcd36225ff6e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 22:11:49 +0000 Subject: replace a few remaining uppercase "Polypaudio" occurences with "PulseAudio" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1036 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 13f571e1..d9dcc764 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1262,18 +1262,18 @@ fail: static int sndstat_open(int flags, int *_errno) { static const char sndstat[] = - "Sound Driver:3.8.1a-980706 (Polypaudio Virtual OSS)\n" + "Sound Driver:3.8.1a-980706 (PulseAudio Virtual OSS)\n" "Kernel: POSIX\n" "Config options: 0\n" "\n" "Installed drivers:\n" - "Type 255: Polypaudio Virtual OSS\n" + "Type 255: PulseAudio Virtual OSS\n" "\n" "Card config:\n" - "Polypaudio Virtual OSS\n" + "PulseAudio Virtual OSS\n" "\n" "Audio devices:\n" - "0: Polypaudio Virtual OSS\n" + "0: PulseAudio Virtual OSS\n" "\n" "Synth devices: NOT ENABLED IN CONFIG\n" "\n" @@ -1282,7 +1282,7 @@ static int sndstat_open(int flags, int *_errno) { "Timers:\n" "\n" "Mixers:\n" - "0: Polypaudio Virtual OSS\n"; + "0: PulseAudio Virtual OSS\n"; char fn[] = "/tmp/padsp-sndstat-XXXXXX"; mode_t u; @@ -1501,7 +1501,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno memset(mi, 0, sizeof(mixer_info)); strncpy(mi->id, "POLYPAUDIO", sizeof(mi->id)); - strncpy(mi->name, "Polypaudio Virtual OSS", sizeof(mi->name)); + strncpy(mi->name, "PulseAudio Virtual OSS", sizeof(mi->name)); pa_threaded_mainloop_lock(i->mainloop); mi->modify_counter = i->volume_modify_count; pa_threaded_mainloop_unlock(i->mainloop); -- cgit From 230f97a4a4dc22510a19add8b2df0533a359846c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 23:56:54 +0000 Subject: s/POLYP/PULSE/g git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1041 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index d9dcc764..af89f8fb 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1500,7 +1500,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_INFO\n"); memset(mi, 0, sizeof(mixer_info)); - strncpy(mi->id, "POLYPAUDIO", sizeof(mi->id)); + strncpy(mi->id, "PULSEAUDIO", sizeof(mi->id)); strncpy(mi->name, "PulseAudio Virtual OSS", sizeof(mi->name)); pa_threaded_mainloop_lock(i->mainloop); mi->modify_counter = i->volume_modify_count; -- cgit From 07edf591771e719a5616ca11319f644fbf66f576 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 20 Jun 2006 15:36:28 +0000 Subject: Make fix_metrics() exit early so that it doesn't spam the output needlessly. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1046 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index af89f8fb..3b8ecbf1 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -673,6 +673,13 @@ static void fix_metrics(fd_info *i) { char t[PA_SAMPLE_SPEC_SNPRINT_MAX]; fs = pa_frame_size(&i->sample_spec); + + /* Don't fix things more than necessary */ + if ((i->fragment_size % fs) == 0 && + i->n_fragments >= 2 && + i->fragment_size > 0) + return; + i->fragment_size = (i->fragment_size/fs)*fs; /* Number of fragments set? */ -- cgit From 1040b69cf2fc6175a1069226a93ec66f1a092ad0 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 20 Jun 2006 15:45:10 +0000 Subject: Warn when applications use SNDCTL_DSP_GET[IO]PTR even when they shouldn't. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1047 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 3b8ecbf1..3b2294f7 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1992,10 +1992,19 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) break; } - + + case SNDCTL_DSP_GETIPTR: + debug(DEBUG_LEVEL_NORMAL, __FILE__": invalid ioctl SNDCTL_DSP_GETIPTR\n"); + goto inval; + + case SNDCTL_DSP_GETOPTR: + debug(DEBUG_LEVEL_NORMAL, __FILE__": invalid ioctl SNDCTL_DSP_GETOPTR\n"); + goto inval; + default: debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); +inval: *_errno = EINVAL; goto fail; } -- cgit From 320bedb58032d33a2bd31978c95b8f17d07c9872 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 20 Jun 2006 16:43:46 +0000 Subject: Fix handling of the io flags in duplex mode. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1048 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 3b2294f7..f493f7e5 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -75,6 +75,7 @@ struct fd_info { pa_stream *rec_stream; pa_io_event *io_event; + pa_io_event_flags_t io_flags; void *buf; size_t rec_offset; @@ -557,6 +558,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { i->play_stream = NULL; i->rec_stream = NULL; i->io_event = NULL; + i->io_flags = 0; pthread_mutex_init(&i->mutex, NULL); i->ref = 1; i->buf = NULL; @@ -709,13 +711,10 @@ static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { if (i->io_event) { pa_mainloop_api *api; - pa_io_event_flags_t flags; size_t n; api = pa_threaded_mainloop_get_api(i->mainloop); - flags = 0; - if (s == i->play_stream) { n = pa_stream_writable_size(i->play_stream); if (n == (size_t)-1) { @@ -724,7 +723,9 @@ static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { } if (n >= i->fragment_size) - flags |= PA_IO_EVENT_INPUT; + i->io_flags |= PA_IO_EVENT_INPUT; + else + i->io_flags &= ~PA_IO_EVENT_INPUT; } if (s == i->rec_stream) { @@ -735,10 +736,12 @@ static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { } if (n >= i->fragment_size) - flags |= PA_IO_EVENT_OUTPUT; + i->io_flags |= PA_IO_EVENT_OUTPUT; + else + i->io_flags &= ~PA_IO_EVENT_OUTPUT; } - api->io_enable(i->io_event, flags); + api->io_enable(i->io_event, i->io_flags); } } @@ -757,6 +760,7 @@ static void fd_info_shutdown(fd_info *i) { api = pa_threaded_mainloop_get_api(i->mainloop); api->io_free(i->io_event); i->io_event = NULL; + i->io_flags = 0; } if (i->thread_fd >= 0) { @@ -767,13 +771,10 @@ static void fd_info_shutdown(fd_info *i) { static int fd_info_copy_data(fd_info *i, int force) { size_t n; - pa_io_event_flags_t flags; if (!i->play_stream && !i->rec_stream) return -1; - flags = 0; - if ((i->play_stream) && (pa_stream_get_state(i->play_stream) == PA_STREAM_READY)) { n = pa_stream_writable_size(i->play_stream); @@ -814,7 +815,9 @@ static int fd_info_copy_data(fd_info *i, int force) { } if (n >= i->fragment_size) - flags |= PA_IO_EVENT_INPUT; + i->io_flags |= PA_IO_EVENT_INPUT; + else + i->io_flags &= ~PA_IO_EVENT_INPUT; } if ((i->rec_stream) && (pa_stream_get_state(i->rec_stream) == PA_STREAM_READY)) { @@ -867,14 +870,16 @@ static int fd_info_copy_data(fd_info *i, int force) { } if (n >= i->fragment_size) - flags |= PA_IO_EVENT_OUTPUT; + i->io_flags |= PA_IO_EVENT_OUTPUT; + else + i->io_flags &= ~PA_IO_EVENT_OUTPUT; } if (i->io_event) { pa_mainloop_api *api; api = pa_threaded_mainloop_get_api(i->mainloop); - api->io_enable(i->io_event, flags); + api->io_enable(i->io_event, i->io_flags); } return 0; @@ -1034,7 +1039,6 @@ static int dsp_open(int flags, int *_errno) { pa_mainloop_api *api; int ret; int f; - pa_io_event_flags_t ioflags; debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open()\n"); @@ -1056,23 +1060,23 @@ static int dsp_open(int flags, int *_errno) { switch (flags & O_ACCMODE) { case O_RDONLY: - ioflags = PA_IO_EVENT_OUTPUT; + i->io_flags = PA_IO_EVENT_OUTPUT; shutdown(i->thread_fd, SHUT_RD); shutdown(i->app_fd, SHUT_WR); break; case O_WRONLY: - ioflags = PA_IO_EVENT_INPUT; + i->io_flags = PA_IO_EVENT_INPUT; shutdown(i->thread_fd, SHUT_WR); shutdown(i->app_fd, SHUT_RD); break; case O_RDWR: - ioflags = PA_IO_EVENT_INPUT | PA_IO_EVENT_OUTPUT; + i->io_flags = PA_IO_EVENT_INPUT | PA_IO_EVENT_OUTPUT; break; default: return -1; } - if (!(i->io_event = api->io_new(api, i->thread_fd, ioflags, io_event_cb, i))) + if (!(i->io_event = api->io_new(api, i->thread_fd, i->io_flags, io_event_cb, i))) goto fail; pa_threaded_mainloop_unlock(i->mainloop); -- cgit From a87c43d61e950b60b44e7e786116dd1e2fad4dc6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Jul 2006 00:18:21 +0000 Subject: Don't call pa_path_get_filename() anymore since it is implicitly called by pa_get_binary_name() anyway git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1078 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index f493f7e5..b1636754 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -408,7 +408,7 @@ static const char *client_name(char *buf, size_t n) { return e; if (pa_get_binary_name(p, sizeof(p))) - snprintf(buf, n, "OSS Emulation[%s]", pa_path_get_filename(p)); + snprintf(buf, n, "OSS Emulation[%s]", p); else snprintf(buf, n, "OSS"); -- cgit From ba31adcf3ebb542931fb6d66f2e1fc7689dfc712 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Jul 2006 23:20:27 +0000 Subject: make pulseaudio compile again on FreeBSD (patch from Diego "Flameeyes" Petteno) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1096 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 6 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index b1636754..32cb5f9a 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,9 @@ #include #include +#ifdef __linux__ #include +#endif #include #include @@ -101,8 +104,10 @@ static int (*_ioctl)(int, int, void*) = NULL; static int (*_close)(int) = NULL; static int (*_open)(const char *, int, mode_t) = NULL; static FILE* (*_fopen)(const char *path, const char *mode) = NULL; +#ifdef HAVE_OPEN64 static int (*_open64)(const char *, int, mode_t) = NULL; static FILE* (*_fopen64)(const char *path, const char *mode) = NULL; +#endif static int (*_fclose)(FILE *f) = NULL; static int (*_access)(const char *, int) = NULL; @@ -1302,7 +1307,11 @@ static int sndstat_open(int flags, int *_errno) { debug(DEBUG_LEVEL_NORMAL, __FILE__": sndstat_open()\n"); - if (flags != O_RDONLY && flags != (O_RDONLY|O_LARGEFILE)) { + if (flags != O_RDONLY +#ifdef O_LARGEFILE + && flags != (O_RDONLY|O_LARGEFILE) +#endif + ) { *_errno = EACCES; debug(DEBUG_LEVEL_NORMAL, __FILE__": bad access!\n"); goto fail; @@ -1349,8 +1358,12 @@ int open(const char *filename, int flags, ...) { debug(DEBUG_LEVEL_VERBOSE, __FILE__": open(%s)\n", filename); va_start(args, flags); - if (flags & O_CREAT) + if (flags & O_CREAT) { + if (sizeof(mode_t) < sizeof(int)) + mode = va_arg(args, int); + else mode = va_arg(args, mode_t); + } va_end(args); if (!function_enter()) { @@ -1587,6 +1600,7 @@ static int map_format_back(pa_sample_format_t format) { } static int dsp_flush_fd(int fd) { +#ifdef SIOCINQ int l; if (ioctl(fd, SIOCINQ, &l) < 0) { @@ -1605,6 +1619,10 @@ static int dsp_flush_fd(int fd) { } return 0; +#else +# warning "Your platform does not support SIOCINQ, something might not work as intended." + return 0; +#endif } static int dsp_flush_socket(fd_info *i) { @@ -1629,6 +1647,7 @@ static int dsp_flush_socket(fd_info *i) { } static int dsp_empty_socket(fd_info *i) { +#ifdef SIOCINQ int ret = -1; /* Empty the socket */ @@ -1652,6 +1671,10 @@ static int dsp_empty_socket(fd_info *i) { } return ret; +#else +# warning "Your platform does not support SIOCINQ, something might not work as intended." + return 0; +#endif } static int dsp_drain(fd_info *i) { @@ -1864,7 +1887,11 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_GETCAPS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CAPS\n"); - *(int*) argp = DSP_CAP_DUPLEX | DSP_CAP_MULTI; + *(int*) argp = DSP_CAP_DUPLEX +#ifdef DSP_CAP_MULTI + | DSP_CAP_MULTI +#endif + ; break; case SNDCTL_DSP_GETODELAY: { @@ -1895,11 +1922,15 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) } exit_loop: - + +#ifdef SIOCINQ if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); else *(int*) argp += l; +#else +# warning "Your platform does not support SIOCINQ, something might not work as intended." +#endif pa_threaded_mainloop_unlock(i->mainloop); @@ -1946,7 +1977,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_GETOSPACE: case SNDCTL_DSP_GETISPACE: { audio_buf_info *bi = (audio_buf_info*) argp; - int l; + int l = 0; size_t k = 0; if (request == SNDCTL_DSP_GETOSPACE) @@ -1965,10 +1996,14 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) } else k = i->fragment_size * i->n_fragments; +#ifdef SIOCINQ if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); l = 0; } +#else +# warning "Your platform does not dsp_flush_fd, something might not work as intended." +#endif bi->bytes = k > (size_t) l ? k - l : 0; } else { @@ -1978,11 +2013,14 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) } else k = 0; +#ifdef SIOCINQ if (ioctl(i->app_fd, SIOCINQ, &l) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); l = 0; } - +#else +# warning "Your platform does not dsp_flush_fd, something might not work as intended." +#endif bi->bytes = k + l; } @@ -2104,6 +2142,8 @@ int access(const char *pathname, int mode) { return 0; } +#ifdef HAVE_OPEN64 + int open64(const char *filename, int flags, ...) { va_list args; mode_t mode = 0; @@ -2126,6 +2166,8 @@ int open64(const char *filename, int flags, ...) { return open(filename, flags, mode); } +#endif + FILE* fopen(const char *filename, const char *mode) { FILE *f = NULL; int fd; @@ -2168,6 +2210,8 @@ FILE* fopen(const char *filename, const char *mode) { return f; } +#ifdef HAVE_OPEN64 + FILE *fopen64(const char *filename, const char *mode) { debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen64(%s)\n", filename); @@ -2183,6 +2227,8 @@ FILE *fopen64(const char *filename, const char *mode) { return fopen(filename, mode); } +#endif + int fclose(FILE *f) { fd_info *i; -- cgit From 078420a9d2b2532062f30263d067e76735a30349 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 30 Aug 2006 13:02:29 +0000 Subject: We need to have a callback when changing volume or we might deadlock. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1345 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 32cb5f9a..c765b693 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1487,9 +1487,9 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno pa_operation *o; if (request == SOUND_MIXER_READ_PCM) - o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, pv, NULL, NULL); + o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, pv, context_success_cb, i); else - o = pa_context_set_source_volume_by_index(i->context, i->source_index, pv, NULL, NULL); + o = pa_context_set_source_volume_by_index(i->context, i->source_index, pv, context_success_cb, i); if (!o) debug(DEBUG_LEVEL_NORMAL, __FILE__":Failed set volume: %s", pa_strerror(pa_context_errno(i->context))); -- cgit From 0f6098bf6428b17bbff2b2d6f4e8ead0d43d7f3a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 31 Aug 2006 15:31:33 +0000 Subject: work around bug in firefox which apparently misuses access() as NULL pointer test. Original patch by "alon". (Closes #27) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1352 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index c765b693..ddb732f0 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -2121,6 +2121,13 @@ int close(int fd) { } int access(const char *pathname, int mode) { + + if (!pathname) { + /* Firefox needs this. See #27 */ + errno = EFAULT; + return -1; + } + debug(DEBUG_LEVEL_VERBOSE, __FILE__": access(%s)\n", pathname); if (strcmp(pathname, "/dev/dsp") != 0 && -- cgit From 5fa9cdb6b4be9f5998af462a858124a528914bf3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 2 Sep 2006 12:03:18 +0000 Subject: Merge FreeBSD compatibility patch (from Flameeyes) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1359 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index ddb732f0..dfef3f3a 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -53,6 +53,11 @@ #include #include +/* On some systems SIOCINQ isn't defined, but FIONREAD is just an alias */ +#if !defined(SIOCINQ) && defined(FIONREAD) +# define SIOCINQ FIONREAD +#endif + typedef enum { FD_INFO_MIXER, FD_INFO_STREAM, -- cgit From 65691997782da950f1e2f38700321e635cc5f37c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 6 Sep 2006 19:47:53 +0000 Subject: implement a few more ioctl()s, including a subset of SNDCTL_DSP_GETOPTR. Just enough to make JavaSound work. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1373 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 5 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index dfef3f3a..b20f0d06 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -93,6 +93,8 @@ struct fd_info { pa_cvolume sink_volume, source_volume; uint32_t sink_index, source_index; int volume_modify_count; + + int optr_n_blocks; PA_LLIST_FIELDS(fd_info); }; @@ -579,6 +581,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { i->volume_modify_count = 0; i->sink_index = (uint32_t) -1; i->source_index = (uint32_t) -1; + i->optr_n_blocks = 0; PA_LLIST_INIT(fd_info, i); reset_params(i); @@ -1952,6 +1955,8 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) free_streams(i); dsp_flush_socket(i); reset_params(i); + + i->optr_n_blocks = 0; pa_threaded_mainloop_unlock(i->mainloop); break; @@ -2040,14 +2045,76 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) break; } + case SOUND_PCM_READ_RATE: + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_RATE\n"); + + pa_threaded_mainloop_lock(i->mainloop); + *(int*) argp = i->sample_spec.rate; + pa_threaded_mainloop_unlock(i->mainloop); + break; + + case SOUND_PCM_READ_CHANNELS: + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_CHANNELS\n"); + + pa_threaded_mainloop_lock(i->mainloop); + *(int*) argp = i->sample_spec.channels; + pa_threaded_mainloop_unlock(i->mainloop); + break; + + case SOUND_PCM_READ_BITS: + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_BITS\n"); + + pa_threaded_mainloop_lock(i->mainloop); + *(int*) argp = pa_sample_size(&i->sample_spec)*8; + pa_threaded_mainloop_unlock(i->mainloop); + break; + + case SNDCTL_DSP_GETOPTR: { + count_info *info; + + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETODELAY\n"); + + info = (count_info*) argp; + memset(info, 0, sizeof(*info)); + + pa_threaded_mainloop_lock(i->mainloop); + + for (;;) { + pa_usec_t usec; + + PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, exit_loop); + + if (pa_stream_get_time(i->play_stream, &usec) >= 0) { + size_t k = pa_usec_to_bytes(usec, &i->sample_spec); + int m; + + info->bytes = (int) k; + m = k / i->fragment_size; + info->blocks = m - i->optr_n_blocks; + i->optr_n_blocks = m; + + break; + } + + if (pa_context_errno(i->context) != PA_ERR_NODATA) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i->context))); + break; + } + + pa_threaded_mainloop_wait(i->mainloop); + } + + pa_threaded_mainloop_unlock(i->mainloop); + + debug(DEBUG_LEVEL_NORMAL, __FILE__": GETOPTR bytes=%i, blocks=%i, ptr=%i\n", info->bytes, info->blocks, info->ptr); + + break; + } + case SNDCTL_DSP_GETIPTR: debug(DEBUG_LEVEL_NORMAL, __FILE__": invalid ioctl SNDCTL_DSP_GETIPTR\n"); goto inval; - - case SNDCTL_DSP_GETOPTR: - debug(DEBUG_LEVEL_NORMAL, __FILE__": invalid ioctl SNDCTL_DSP_GETOPTR\n"); - goto inval; - + default: debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); -- cgit From 66ec460845d2e3df08a447b3ba93ee1006b04846 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 6 Sep 2006 21:37:09 +0000 Subject: fix a bogus debug line git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1374 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index b20f0d06..883ffbd9 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -2072,7 +2072,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_GETOPTR: { count_info *info; - debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETODELAY\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETOPTR\n"); info = (count_info*) argp; memset(info, 0, sizeof(*info)); -- cgit From 5f828c2c3df6a788b5f8be3422bd355b91104791 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 14 Sep 2006 14:56:31 +0000 Subject: Fix debug output for SNDCTL_DSP_SETFRAGMENT. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1396 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 883ffbd9..d947f697 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1875,7 +1875,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) break; case SNDCTL_DSP_SETFRAGMENT: - debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%8x\n", *(int*) argp); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%08x\n", *(int*) argp); pa_threaded_mainloop_lock(i->mainloop); -- cgit From 29ab939570ee739570a6bfaa6569bd6f6135df56 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 14 Sep 2006 16:00:57 +0000 Subject: Stop using x86-isms and use ISO C (oversized shifts are undefined). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1397 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index d947f697..c7bfe5ab 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1879,7 +1879,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_lock(i->mainloop); - i->fragment_size = 1 << (*(int*) argp); + i->fragment_size = 1 << ((*(int*) argp) & 31); i->n_fragments = (*(int*) argp) >> 16; /* 0x7FFF means that we can set whatever we like */ -- cgit From 6ca819354cabdaeda0b122535a50fa49924d8d2d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 6 Nov 2006 10:17:39 +0000 Subject: The OSS spec is unclear what should happen when a reset is requested. Let's have a nicer attitude and keep as much settings as possible. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1406 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index c7bfe5ab..5d96a984 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1003,12 +1003,21 @@ static void free_streams(fd_info *i) { pa_stream_disconnect(i->play_stream); pa_stream_unref(i->play_stream); i->play_stream = NULL; + i->io_flags |= PA_IO_EVENT_INPUT; } if (i->rec_stream) { pa_stream_disconnect(i->rec_stream); pa_stream_unref(i->rec_stream); i->rec_stream = NULL; + i->io_flags |= PA_IO_EVENT_OUTPUT; + } + + if (i->io_event) { + pa_mainloop_api *api; + + api = pa_threaded_mainloop_get_api(i->mainloop); + api->io_enable(i->io_event, i->io_flags); } } @@ -1954,7 +1963,6 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) free_streams(i); dsp_flush_socket(i); - reset_params(i); i->optr_n_blocks = 0; -- cgit From d4ca81fc2e8f480ec3f244b5f23e9303b5816452 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 6 Nov 2006 13:16:15 +0000 Subject: Fix some missing line breaks. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1410 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 5d96a984..a8ac8667 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -191,7 +191,7 @@ do { \ #define CONTEXT_CHECK_DEAD_GOTO(i, label) do { \ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \ - debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ + debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ } while(0); @@ -199,7 +199,7 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \ #define PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, label) do { \ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ !(i)->play_stream || pa_stream_get_state((i)->play_stream) != PA_STREAM_READY) { \ - debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ + debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ } while(0); @@ -207,7 +207,7 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ #define RECORD_STREAM_CHECK_DEAD_GOTO(i, label) do { \ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ !(i)->rec_stream || pa_stream_get_state((i)->rec_stream) != PA_STREAM_READY) { \ - debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ + debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ } while(0); -- cgit From 521daf6f0ac4fa6a2fbfb5d523c0c743342dca2b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 4 Jan 2007 13:43:45 +0000 Subject: Huge trailing whitespace cleanup. Let's keep the tree pure from here on, mmmkay? git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1418 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 278 +++++++++++++++++++++++++++--------------------------- 1 file changed, 139 insertions(+), 139 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index a8ac8667..679a5d01 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -69,7 +69,7 @@ struct fd_info { pthread_mutex_t mutex; int ref; int unusable; - + fd_info_type_t type; int app_fd, thread_fd; @@ -95,7 +95,7 @@ struct fd_info { int volume_modify_count; int optr_n_blocks; - + PA_LLIST_FIELDS(fd_info); }; @@ -248,7 +248,7 @@ static int padsp_disabled(void) { * -> disable /dev/dsp emulation, bit 2 -> disable /dev/sndstat * emulation, bit 3 -> disable /dev/mixer emulation. Hence a value * of 7 disables padsp entirely. */ - + pthread_mutex_lock(&func_mutex); if (!sym_resolved) { sym = (int*) dlsym(RTLD_DEFAULT, "__padsp_disabled__"); @@ -259,14 +259,14 @@ static int padsp_disabled(void) { if (!sym) return 0; - + return *sym; } static int dsp_cloak_enable(void) { if (padsp_disabled() & 1) return 0; - + if (getenv("PADSP_NO_DSP")) return 0; @@ -302,7 +302,7 @@ static int function_enter(void) { /* Avoid recursive calls */ static pthread_once_t recursion_key_once = PTHREAD_ONCE_INIT; pthread_once(&recursion_key_once, recursion_key_alloc); - + if (pthread_getspecific(recursion_key)) return 0; @@ -320,10 +320,10 @@ static void fd_info_free(fd_info *i) { debug(DEBUG_LEVEL_NORMAL, __FILE__": freeing fd info (fd=%i)\n", i->app_fd); dsp_drain(i); - + if (i->mainloop) pa_threaded_mainloop_stop(i->mainloop); - + if (i->play_stream) { pa_stream_disconnect(i->play_stream); pa_stream_unref(i->play_stream); @@ -338,7 +338,7 @@ static void fd_info_free(fd_info *i) { pa_context_disconnect(i->context); pa_context_unref(i->context); } - + if (i->mainloop) pa_threaded_mainloop_free(i->mainloop); @@ -360,7 +360,7 @@ static void fd_info_free(fd_info *i) { static fd_info *fd_info_ref(fd_info *i) { assert(i); - + pthread_mutex_lock(&i->mutex); assert(i->ref >= 1); i->ref++; @@ -404,7 +404,7 @@ static void context_state_cb(pa_context *c, void *userdata) { static void reset_params(fd_info *i) { assert(i); - + i->sample_spec.format = PA_SAMPLE_U8; i->sample_spec.channels = 1; i->sample_spec.rate = 8000; @@ -418,7 +418,7 @@ static const char *client_name(char *buf, size_t n) { if ((e = getenv("PADSP_CLIENT_NAME"))) return e; - + if (pa_get_binary_name(p, sizeof(p))) snprintf(buf, n, "OSS Emulation[%s]", p); else @@ -440,7 +440,7 @@ static void atfork_prepare(void) { fd_info *i; debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_prepare() enter\n"); - + function_enter(); pthread_mutex_lock(&fd_infos_mutex); @@ -452,13 +452,13 @@ static void atfork_prepare(void) { pthread_mutex_lock(&func_mutex); - + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_prepare() exit\n"); } static void atfork_parent(void) { fd_info *i; - + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_parent() enter\n"); pthread_mutex_unlock(&func_mutex); @@ -471,19 +471,19 @@ static void atfork_parent(void) { pthread_mutex_unlock(&fd_infos_mutex); function_exit(); - + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_parent() exit\n"); } static void atfork_child(void) { fd_info *i; - + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_child() enter\n"); /* We do only the bare minimum to get all fds closed */ pthread_mutex_init(&func_mutex, NULL); pthread_mutex_init(&fd_infos_mutex, NULL); - + for (i = fd_infos; i; i = i->next) { pthread_mutex_init(&i->mutex, NULL); @@ -556,7 +556,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { signal(SIGPIPE, SIG_IGN); /* Yes, ugly as hell */ pthread_once(&install_atfork_once, install_atfork); - + if (!(i = malloc(sizeof(fd_info)))) { *_errno = ENOMEM; goto fail; @@ -638,12 +638,12 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { unlock_and_fail: pa_threaded_mainloop_unlock(i->mainloop); - + fail: if (i) fd_info_unref(i); - + return NULL; } @@ -671,7 +671,7 @@ static fd_info* fd_info_find(int fd) { fd_info *i; pthread_mutex_lock(&fd_infos_mutex); - + for (i = fd_infos; i; i = i->next) if (i->app_fd == fd && !i->unusable) { fd_info_ref(i); @@ -679,7 +679,7 @@ static fd_info* fd_info_find(int fd) { } pthread_mutex_unlock(&fd_infos_mutex); - + return i; } @@ -907,7 +907,7 @@ static void stream_state_cb(pa_stream *s, void * userdata) { case PA_STREAM_READY: debug(DEBUG_LEVEL_NORMAL, __FILE__": stream established.\n"); break; - + case PA_STREAM_FAILED: debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); fd_info_shutdown(i); @@ -923,7 +923,7 @@ static void stream_state_cb(pa_stream *s, void * userdata) { static int create_playback_stream(fd_info *i) { pa_buffer_attr attr; int n; - + assert(i); fix_metrics(i); @@ -942,7 +942,7 @@ static int create_playback_stream(fd_info *i) { attr.tlength = i->fragment_size * i->n_fragments; attr.prebuf = i->fragment_size; attr.minreq = i->fragment_size; - + if (pa_stream_connect_playback(i->play_stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; @@ -952,7 +952,7 @@ static int create_playback_stream(fd_info *i) { setsockopt(i->app_fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)); n = i->fragment_size; setsockopt(i->thread_fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)); - + return 0; fail: @@ -962,7 +962,7 @@ fail: static int create_record_stream(fd_info *i) { pa_buffer_attr attr; int n; - + assert(i); fix_metrics(i); @@ -979,7 +979,7 @@ static int create_record_stream(fd_info *i) { memset(&attr, 0, sizeof(attr)); attr.maxlength = i->fragment_size * (i->n_fragments+1); attr.fragsize = i->fragment_size; - + if (pa_stream_connect_record(i->rec_stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; @@ -989,7 +989,7 @@ static int create_record_stream(fd_info *i) { setsockopt(i->app_fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)); n = i->fragment_size; setsockopt(i->thread_fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)); - + return 0; fail: @@ -1025,7 +1025,7 @@ static void io_event_cb(pa_mainloop_api *api, pa_io_event *e, int fd, pa_io_even fd_info *i = userdata; pa_threaded_mainloop_signal(i->mainloop, 0); - + if (flags & PA_IO_EVENT_INPUT) { if (!i->play_stream) { @@ -1035,7 +1035,7 @@ static void io_event_cb(pa_mainloop_api *api, pa_io_event *e, int fd, pa_io_even if (fd_info_copy_data(i, 0) < 0) goto fail; } - + } else if (flags & PA_IO_EVENT_OUTPUT) { if (!i->rec_stream) { @@ -1050,7 +1050,7 @@ static void io_event_cb(pa_mainloop_api *api, pa_io_event *e, int fd, pa_io_even goto fail; return; - + fail: /* We can't do anything better than removing the event source */ fd_info_shutdown(i); @@ -1100,7 +1100,7 @@ static int dsp_open(int flags, int *_errno) { if (!(i->io_event = api->io_new(api, i->thread_fd, i->io_flags, io_event_cb, i))) goto fail; - + pa_threaded_mainloop_unlock(i->mainloop); debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open() succeeded, fd=%i\n", i->app_fd); @@ -1108,7 +1108,7 @@ static int dsp_open(int flags, int *_errno) { fd_info_add_to_list(i); ret = i->app_fd; fd_info_unref(i); - + return ret; fail: @@ -1116,7 +1116,7 @@ fail: if (i) fd_info_unref(i); - + *_errno = EIO; debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open() failed\n"); @@ -1138,7 +1138,7 @@ static void sink_info_cb(pa_context *context, const pa_sink_info *si, int eol, v if (!pa_cvolume_equal(&i->sink_volume, &si->volume)) i->volume_modify_count++; - + i->sink_volume = si->volume; i->sink_index = si->index; @@ -1160,7 +1160,7 @@ static void source_info_cb(pa_context *context, const pa_source_info *si, int eo if (!pa_cvolume_equal(&i->source_volume, &si->volume)) i->volume_modify_count++; - + i->source_volume = si->volume; i->source_index = si->index; @@ -1193,13 +1193,13 @@ static int mixer_open(int flags, int *_errno) { debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open()\n"); - if (!(i = fd_info_new(FD_INFO_MIXER, _errno))) + if (!(i = fd_info_new(FD_INFO_MIXER, _errno))) return -1; - + pa_threaded_mainloop_lock(i->mainloop); pa_context_set_subscribe_callback(i->context, subscribe_cb, i); - + if (!(o = pa_context_subscribe(i->context, PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE, context_success_cb, i))) { debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; @@ -1274,7 +1274,7 @@ static int mixer_open(int flags, int *_errno) { fd_info_add_to_list(i); ret = i->app_fd; fd_info_unref(i); - + return ret; fail: @@ -1285,7 +1285,7 @@ fail: if (i) fd_info_unref(i); - + *_errno = EIO; debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open() failed\n"); @@ -1323,7 +1323,7 @@ static int sndstat_open(int flags, int *_errno) { int e; debug(DEBUG_LEVEL_NORMAL, __FILE__": sndstat_open()\n"); - + if (flags != O_RDONLY #ifdef O_LARGEFILE && flags != (O_RDONLY|O_LARGEFILE) @@ -1401,16 +1401,16 @@ int open(const char *filename, int flags, ...) { } function_exit(); - + if (_errno) errno = _errno; - + return r; } static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { int ret = -1; - + switch (request) { case SOUND_MIXER_READ_DEVMASK : debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_DEVMASK\n"); @@ -1423,7 +1423,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno *(int*) argp = SOUND_MASK_IGAIN; break; - + case SOUND_MIXER_READ_STEREODEVS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_STEREODEVS\n"); @@ -1434,7 +1434,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno if (i->source_volume.channels > 1) *(int*) argp |= SOUND_MASK_IGAIN; pa_threaded_mainloop_unlock(i->mainloop); - + break; case SOUND_MIXER_READ_RECSRC: @@ -1452,7 +1452,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno *(int*) argp = 0; break; - + case SOUND_MIXER_READ_PCM: case SOUND_MIXER_READ_IGAIN: { pa_cvolume *v; @@ -1515,23 +1515,23 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno i->operation_success = 0; while (pa_operation_get_state(o) != PA_OPERATION_DONE) { CONTEXT_CHECK_DEAD_GOTO(i, exit_loop); - + pa_threaded_mainloop_wait(i->mainloop); } exit_loop: - + if (!i->operation_success) debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to set volume: %s\n", pa_strerror(pa_context_errno(i->context))); pa_operation_unref(o); } - + /* We don't wait for completion here */ i->volume_modify_count++; } - + pa_threaded_mainloop_unlock(i->mainloop); - + break; } @@ -1548,7 +1548,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno pa_threaded_mainloop_unlock(i->mainloop); break; } - + default: debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); @@ -1557,44 +1557,44 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno } ret = 0; - + fail: - + return ret; } static int map_format(int *fmt, pa_sample_spec *ss) { - + switch (*fmt) { case AFMT_MU_LAW: ss->format = PA_SAMPLE_ULAW; break; - + case AFMT_A_LAW: ss->format = PA_SAMPLE_ALAW; break; - + case AFMT_S8: *fmt = AFMT_U8; /* fall through */ case AFMT_U8: ss->format = PA_SAMPLE_U8; break; - + case AFMT_U16_BE: *fmt = AFMT_S16_BE; /* fall through */ case AFMT_S16_BE: ss->format = PA_SAMPLE_S16BE; break; - + case AFMT_U16_LE: *fmt = AFMT_S16_LE; /* fall through */ case AFMT_S16_LE: ss->format = PA_SAMPLE_S16LE; break; - + default: ss->format = PA_SAMPLE_S16NE; *fmt = AFMT_S16_NE; @@ -1666,14 +1666,14 @@ static int dsp_flush_socket(fd_info *i) { static int dsp_empty_socket(fd_info *i) { #ifdef SIOCINQ int ret = -1; - + /* Empty the socket */ for (;;) { int l; - + if (i->thread_fd < 0) break; - + if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ: %s\n", strerror(errno)); break; @@ -1683,7 +1683,7 @@ static int dsp_empty_socket(fd_info *i) { ret = 0; break; } - + pa_threaded_mainloop_wait(i->mainloop); } @@ -1700,19 +1700,19 @@ static int dsp_drain(fd_info *i) { if (!i->mainloop) return 0; - + debug(DEBUG_LEVEL_NORMAL, __FILE__": Draining.\n"); pa_threaded_mainloop_lock(i->mainloop); if (dsp_empty_socket(i) < 0) goto fail; - + if (!i->play_stream) goto fail; debug(DEBUG_LEVEL_NORMAL, __FILE__": Really draining.\n"); - + if (!(o = pa_stream_drain(i->play_stream, stream_success_cb, i))) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; @@ -1721,7 +1721,7 @@ static int dsp_drain(fd_info *i) { i->operation_success = 0; while (pa_operation_get_state(o) != PA_OPERATION_DONE) { PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail); - + pa_threaded_mainloop_wait(i->mainloop); } @@ -1731,9 +1731,9 @@ static int dsp_drain(fd_info *i) { } r = 0; - + fail: - + if (o) pa_operation_unref(o); @@ -1755,7 +1755,7 @@ static int dsp_trigger(fd_info *i) { goto fail; debug(DEBUG_LEVEL_NORMAL, __FILE__": Triggering.\n"); - + if (!(o = pa_stream_trigger(i->play_stream, stream_success_cb, i))) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; @@ -1764,7 +1764,7 @@ static int dsp_trigger(fd_info *i) { i->operation_success = 0; while (!pa_operation_get_state(o) != PA_OPERATION_DONE) { PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail); - + pa_threaded_mainloop_wait(i->mainloop); } @@ -1774,9 +1774,9 @@ static int dsp_trigger(fd_info *i) { } r = 0; - + fail: - + if (o) pa_operation_unref(o); @@ -1787,11 +1787,11 @@ fail: static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { int ret = -1; - + switch (request) { case SNDCTL_DSP_SETFMT: { debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp); - + pa_threaded_mainloop_lock(i->mainloop); if (*(int*) argp == AFMT_QUERY) @@ -1804,12 +1804,12 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_unlock(i->mainloop); break; } - + case SNDCTL_DSP_SPEED: { pa_sample_spec ss; int valid; char t[256]; - + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SPEED: %i\n", *(int*) argp); pa_threaded_mainloop_lock(i->mainloop); @@ -1821,7 +1821,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) i->sample_spec = ss; free_streams(i); } - + debug(DEBUG_LEVEL_NORMAL, __FILE__": ss: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); pa_threaded_mainloop_unlock(i->mainloop); @@ -1833,24 +1833,24 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) break; } - + case SNDCTL_DSP_STEREO: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_STEREO: %i\n", *(int*) argp); - + pa_threaded_mainloop_lock(i->mainloop); - + i->sample_spec.channels = *(int*) argp ? 2 : 1; free_streams(i); - + pa_threaded_mainloop_unlock(i->mainloop); return 0; case SNDCTL_DSP_CHANNELS: { pa_sample_spec ss; int valid; - + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp); - + pa_threaded_mainloop_lock(i->mainloop); ss = i->sample_spec; @@ -1860,7 +1860,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) i->sample_spec = ss; free_streams(i); } - + pa_threaded_mainloop_unlock(i->mainloop); if (!valid) { @@ -1878,16 +1878,16 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) fix_metrics(i); *(int*) argp = i->fragment_size; - + pa_threaded_mainloop_unlock(i->mainloop); - + break; case SNDCTL_DSP_SETFRAGMENT: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%08x\n", *(int*) argp); - + pa_threaded_mainloop_lock(i->mainloop); - + i->fragment_size = 1 << ((*(int*) argp) & 31); i->n_fragments = (*(int*) argp) >> 16; @@ -1896,14 +1896,14 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) i->n_fragments = 12; free_streams(i); - + pa_threaded_mainloop_unlock(i->mainloop); - + break; - + case SNDCTL_DSP_GETCAPS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CAPS\n"); - + *(int*) argp = DSP_CAP_DUPLEX #ifdef DSP_CAP_MULTI | DSP_CAP_MULTI @@ -1913,13 +1913,13 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_GETODELAY: { int l; - + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETODELAY\n"); - + pa_threaded_mainloop_lock(i->mainloop); *(int*) argp = 0; - + for (;;) { pa_usec_t usec; @@ -1937,10 +1937,10 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_wait(i->mainloop); } - + exit_loop: -#ifdef SIOCINQ +#ifdef SIOCINQ if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); else @@ -1955,39 +1955,39 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) break; } - + case SNDCTL_DSP_RESET: { debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_RESET\n"); - + pa_threaded_mainloop_lock(i->mainloop); free_streams(i); dsp_flush_socket(i); i->optr_n_blocks = 0; - + pa_threaded_mainloop_unlock(i->mainloop); break; } - + case SNDCTL_DSP_GETFMTS: { debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETFMTS\n"); - + *(int*) argp = AFMT_MU_LAW|AFMT_A_LAW|AFMT_U8|AFMT_S16_LE|AFMT_S16_BE; break; } case SNDCTL_DSP_POST: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_POST\n"); - - if (dsp_trigger(i) < 0) + + if (dsp_trigger(i) < 0) *_errno = EIO; break; - case SNDCTL_DSP_SYNC: + case SNDCTL_DSP_SYNC: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SYNC\n"); - - if (dsp_drain(i) < 0) + + if (dsp_drain(i) < 0) *_errno = EIO; break; @@ -2055,36 +2055,36 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SOUND_PCM_READ_RATE: debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_RATE\n"); - + pa_threaded_mainloop_lock(i->mainloop); *(int*) argp = i->sample_spec.rate; pa_threaded_mainloop_unlock(i->mainloop); - break; + break; case SOUND_PCM_READ_CHANNELS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_CHANNELS\n"); - + pa_threaded_mainloop_lock(i->mainloop); *(int*) argp = i->sample_spec.channels; pa_threaded_mainloop_unlock(i->mainloop); - break; + break; case SOUND_PCM_READ_BITS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_BITS\n"); - + pa_threaded_mainloop_lock(i->mainloop); *(int*) argp = pa_sample_size(&i->sample_spec)*8; pa_threaded_mainloop_unlock(i->mainloop); - break; - + break; + case SNDCTL_DSP_GETOPTR: { count_info *info; - + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETOPTR\n"); info = (count_info*) argp; memset(info, 0, sizeof(*info)); - + pa_threaded_mainloop_lock(i->mainloop); for (;;) { @@ -2095,7 +2095,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) if (pa_stream_get_time(i->play_stream, &usec) >= 0) { size_t k = pa_usec_to_bytes(usec, &i->sample_spec); int m; - + info->bytes = (int) k; m = k / i->fragment_size; info->blocks = m - i->optr_n_blocks; @@ -2111,7 +2111,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_wait(i->mainloop); } - + pa_threaded_mainloop_unlock(i->mainloop); debug(DEBUG_LEVEL_NORMAL, __FILE__": GETOPTR bytes=%i, blocks=%i, ptr=%i\n", info->bytes, info->blocks, info->ptr); @@ -2122,7 +2122,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_GETIPTR: debug(DEBUG_LEVEL_NORMAL, __FILE__": invalid ioctl SNDCTL_DSP_GETIPTR\n"); goto inval; - + default: debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); @@ -2132,9 +2132,9 @@ inval: } ret = 0; - + fail: - + return ret; } @@ -2165,14 +2165,14 @@ int ioctl(int fd, unsigned long request, ...) { r = mixer_ioctl(i, request, argp, &_errno); else r = dsp_ioctl(i, request, argp, &_errno); - + fd_info_unref(i); if (_errno) errno = _errno; function_exit(); - + return r; } @@ -2194,7 +2194,7 @@ int close(int fd) { fd_info_remove_from_list(i); fd_info_unref(i); - + function_exit(); return 0; @@ -2207,7 +2207,7 @@ int access(const char *pathname, int mode) { errno = EFAULT; return -1; } - + debug(DEBUG_LEVEL_VERBOSE, __FILE__": access(%s)\n", pathname); if (strcmp(pathname, "/dev/dsp") != 0 && @@ -2236,7 +2236,7 @@ int open64(const char *filename, int flags, ...) { mode_t mode = 0; debug(DEBUG_LEVEL_VERBOSE, __FILE__": open64(%s)\n", filename); - + va_start(args, flags); if (flags & O_CREAT) mode = va_arg(args, mode_t); @@ -2259,7 +2259,7 @@ FILE* fopen(const char *filename, const char *mode) { FILE *f = NULL; int fd; mode_t m; - + debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen(%s)\n", filename); if (strcmp(filename, "/dev/dsp") != 0 && @@ -2293,7 +2293,7 @@ FILE* fopen(const char *filename, const char *mode) { close(fd); return NULL; } - + return f; } @@ -2337,9 +2337,9 @@ int fclose(FILE *f) { /* Dirty trick to avoid that the fd is not freed twice, once by us * and once by the real fclose() */ i->app_fd = -1; - + fd_info_unref(i); - + function_exit(); LOAD_FCLOSE_FUNC(); -- cgit From 19bd9148c5d16a8363065ca128e06037780337ab Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 4 Jan 2007 14:06:24 +0000 Subject: Fix error messages for failure connecting streams. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1419 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 679a5d01..c6025417 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -909,7 +909,15 @@ static void stream_state_cb(pa_stream *s, void * userdata) { break; case PA_STREAM_FAILED: - debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + if (s == i->play_stream) { + debug(DEBUG_LEVEL_NORMAL, + __FILE__": pa_stream_connect_playback() failed: %s\n", + pa_strerror(pa_context_errno(i->context))); + } else if (s == i->rec_stream) { + debug(DEBUG_LEVEL_NORMAL, + __FILE__": pa_stream_connect_record() failed: %s\n", + pa_strerror(pa_context_errno(i->context))); + } fd_info_shutdown(i); break; @@ -981,7 +989,7 @@ static int create_record_stream(fd_info *i) { attr.fragsize = i->fragment_size; if (pa_stream_connect_record(i->rec_stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE) < 0) { - debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } -- cgit From c992ed9c47854338106b38a1d093c4c1bf65e96d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 4 Jan 2007 14:17:57 +0000 Subject: Free stream objects when they've been invalidated. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1420 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index c6025417..aa0ec9dd 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -913,10 +913,14 @@ static void stream_state_cb(pa_stream *s, void * userdata) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + pa_stream_unref(i->play_stream); + i->play_stream = NULL; } else if (s == i->rec_stream) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + pa_stream_unref(i->rec_stream); + i->rec_stream = NULL; } fd_info_shutdown(i); break; -- cgit From 4c0a481f79715c0e783000c75e800d2401c11019 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 4 Jan 2007 14:20:53 +0000 Subject: Report IO error on ioctl() when we're in a fatal error state. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1421 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index aa0ec9dd..b4c5bb0b 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1800,6 +1800,16 @@ fail: static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { int ret = -1; + if (i->thread_fd == -1) { + /* + * We've encountered some fatal error and are just waiting + * for a close. + */ + debug(DEBUG_LEVEL_NORMAL, __FILE__": got ioctl 0x%08lx in fatal error state\n", request); + *_errno = EIO; + return -1; + } + switch (request) { case SNDCTL_DSP_SETFMT: { debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp); -- cgit From 4171f2504a4e0de5c46c3237da009f5355cf57ec Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 19 Jan 2007 08:00:31 +0000 Subject: Make sure we report success for SNDCTL_DSP_SETDUPLEX. (Patch by ZlatkO) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1422 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index b4c5bb0b..2b314a9c 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -2145,6 +2145,11 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) debug(DEBUG_LEVEL_NORMAL, __FILE__": invalid ioctl SNDCTL_DSP_GETIPTR\n"); goto inval; + case SNDCTL_DSP_SETDUPLEX: + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETDUPLEX\n"); + /* this is a no-op */ + break; + default: debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); -- cgit From 06211b7c8fd329137ae9003818543912a87d9898 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 13 Feb 2007 15:35:19 +0000 Subject: Add copyright notices to all relevant files. (based on svn log) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1426 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 2b314a9c..444e1b4d 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, -- cgit From 9ee398107e524ca71a0cfd23e003daa300d1e227 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 7 Mar 2007 09:27:30 +0000 Subject: Add support for SNDCTL_DSP_SETTRIGGER. (closes #56) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1437 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 9 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 444e1b4d..fddd8fb4 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -4,7 +4,7 @@ This file is part of PulseAudio. Copyright 2006 Lennart Poettering - Copyright 2006 Pierre Ossman for Cendio AB + Copyright 2006-2007 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -84,6 +84,8 @@ struct fd_info { pa_context *context; pa_stream *play_stream; pa_stream *rec_stream; + int play_precork; + int rec_precork; pa_io_event *io_event; pa_io_event_flags_t io_flags; @@ -197,7 +199,7 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \ debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ -} while(0); +} while(0) #define PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, label) do { \ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ @@ -205,7 +207,7 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ -} while(0); +} while(0) #define RECORD_STREAM_CHECK_DEAD_GOTO(i, label) do { \ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ @@ -213,7 +215,7 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ -} while(0); +} while(0) static void debug(int level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); @@ -572,6 +574,8 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { i->context = NULL; i->play_stream = NULL; i->rec_stream = NULL; + i->play_precork = 0; + i->rec_precork = 0; i->io_event = NULL; i->io_flags = 0; pthread_mutex_init(&i->mutex, NULL); @@ -937,7 +941,7 @@ static void stream_state_cb(pa_stream *s, void * userdata) { static int create_playback_stream(fd_info *i) { pa_buffer_attr attr; - int n; + int n, flags; assert(i); @@ -958,7 +962,12 @@ static int create_playback_stream(fd_info *i) { attr.prebuf = i->fragment_size; attr.minreq = i->fragment_size; - if (pa_stream_connect_playback(i->play_stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) { + flags = PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE; + if (i->play_precork) { + flags |= PA_STREAM_START_CORKED; + debug(DEBUG_LEVEL_NORMAL, __FILE__": creating stream corked\n"); + } + if (pa_stream_connect_playback(i->play_stream, NULL, &attr, flags, NULL, NULL) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -976,7 +985,7 @@ fail: static int create_record_stream(fd_info *i) { pa_buffer_attr attr; - int n; + int n, flags; assert(i); @@ -995,7 +1004,12 @@ static int create_record_stream(fd_info *i) { attr.maxlength = i->fragment_size * (i->n_fragments+1); attr.fragsize = i->fragment_size; - if (pa_stream_connect_record(i->rec_stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE) < 0) { + flags = PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE; + if (i->rec_precork) { + flags |= PA_STREAM_START_CORKED; + debug(DEBUG_LEVEL_NORMAL, __FILE__": creating stream corked\n"); + } + if (pa_stream_connect_record(i->rec_stream, NULL, &attr, flags) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -1800,6 +1814,44 @@ fail: return 0; } +static int dsp_cork(fd_info *i, pa_stream *s, int b) { + pa_operation *o = NULL; + int r = -1; + + pa_threaded_mainloop_lock(i->mainloop); + + if (!(o = pa_stream_cork(s, b, stream_success_cb, i))) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_cork(): %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + i->operation_success = 0; + while (!pa_operation_get_state(o) != PA_OPERATION_DONE) { + if (s == i->play_stream) + PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail); + else if (s == i->rec_stream) + RECORD_STREAM_CHECK_DEAD_GOTO(i, fail); + + pa_threaded_mainloop_wait(i->mainloop); + } + + if (!i->operation_success) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_cork(): %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + r = 0; + +fail: + + if (o) + pa_operation_unref(o); + + pa_threaded_mainloop_unlock(i->mainloop); + + return 0; +} + static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { int ret = -1; @@ -1929,7 +1981,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_GETCAPS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CAPS\n"); - *(int*) argp = DSP_CAP_DUPLEX + *(int*) argp = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER #ifdef DSP_CAP_MULTI | DSP_CAP_MULTI #endif @@ -2009,6 +2061,32 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) *_errno = EIO; break; + case SNDCTL_DSP_SETTRIGGER: + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETTRIGGER: 0x%08x\n", *(int*) argp); + + if (!i->io_event) { + *_errno = EIO; + break; + } + + i->play_precork = !((*(int*) argp) & PCM_ENABLE_OUTPUT); + + if (i->play_stream) { + if (dsp_cork(i, i->play_stream, !((*(int*) argp) & PCM_ENABLE_OUTPUT)) < 0) + *_errno = EIO; + if (dsp_trigger(i) < 0) + *_errno = EIO; + } + + i->rec_precork = !((*(int*) argp) & PCM_ENABLE_INPUT); + + if (i->rec_stream) { + if (dsp_cork(i, i->rec_stream, !((*(int*) argp) & PCM_ENABLE_INPUT)) < 0) + *_errno = EIO; + } + + break; + case SNDCTL_DSP_SYNC: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SYNC\n"); -- cgit From 8e738ede9b2050a29400d4218b96b68863290857 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 May 2007 15:30:34 +0000 Subject: fix a few obvious copynpaste errors when handling volumes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1444 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index fddd8fb4..0ac48254 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1511,14 +1511,14 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno case SOUND_MIXER_WRITE_IGAIN: { pa_cvolume v, *pv; - if (request == SOUND_MIXER_READ_PCM) + if (request == SOUND_MIXER_WRITE_PCM) debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_PCM\n"); else debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_IGAIN\n"); pa_threaded_mainloop_lock(i->mainloop); - if (request == SOUND_MIXER_READ_PCM) { + if (request == SOUND_MIXER_WRITE_PCM) { v = i->sink_volume; pv = &i->sink_volume; } else { @@ -1532,7 +1532,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno if (!pa_cvolume_equal(pv, &v)) { pa_operation *o; - if (request == SOUND_MIXER_READ_PCM) + if (request == SOUND_MIXER_WRITE_PCM) o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, pv, context_success_cb, i); else o = pa_context_set_source_volume_by_index(i->context, i->source_index, pv, context_success_cb, i); -- cgit From 1e12e0ee8dfdda1632b9c082aba6fc1956813a5b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 29 May 2007 17:24:48 +0000 Subject: Kill spaces on EOL git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1465 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 0ac48254..955bd2f1 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -2230,7 +2230,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETDUPLEX\n"); /* this is a no-op */ break; - + default: debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); -- cgit From 13a4c5290a5a80025c72e9f40c28c2e6437c82e8 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 4 Jun 2007 09:52:03 +0000 Subject: Add support for the poorly documented SNDCTL_DSP_GETTRIGGER. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1466 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 955bd2f1..b9c26f09 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -2061,6 +2061,17 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) *_errno = EIO; break; + case SNDCTL_DSP_GETTRIGGER: + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETTRIGGER\n"); + + *(int*) argp = 0; + if (!i->play_precork) + *(int*) argp |= PCM_ENABLE_OUTPUT; + if (!i->rec_precork) + *(int*) argp |= PCM_ENABLE_INPUT; + + break; + case SNDCTL_DSP_SETTRIGGER: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETTRIGGER: 0x%08x\n", *(int*) argp); -- cgit From 14cbbe1096ef10091a0073009a3c65eb13d2da27 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 11 Jun 2007 11:22:30 +0000 Subject: Support stat() and friends as some programs (audacity) likes to check if the device node is there first. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1467 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index b9c26f09..9a2bad44 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -116,9 +116,17 @@ static int (*_ioctl)(int, int, void*) = NULL; static int (*_close)(int) = NULL; static int (*_open)(const char *, int, mode_t) = NULL; static FILE* (*_fopen)(const char *path, const char *mode) = NULL; +static int (*_stat)(const char *, struct stat *) = NULL; +#ifdef _STAT_VER +static int (*___xstat)(int, const char *, struct stat *) = NULL; +#endif #ifdef HAVE_OPEN64 static int (*_open64)(const char *, int, mode_t) = NULL; static FILE* (*_fopen64)(const char *path, const char *mode) = NULL; +static int (*_stat64)(const char *, struct stat64 *) = NULL; +#ifdef _STAT_VER +static int (*___xstat64)(int, const char *, struct stat64 *) = NULL; +#endif #endif static int (*_fclose)(FILE *f) = NULL; static int (*_access)(const char *, int) = NULL; @@ -170,6 +178,38 @@ do { \ pthread_mutex_unlock(&func_mutex); \ } while(0) +#define LOAD_STAT_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_stat) \ + _stat = (int (*)(const char *, struct stat *)) dlsym_fn(RTLD_NEXT, "stat"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_STAT64_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_stat64) \ + _stat64 = (int (*)(const char *, struct stat64 *)) dlsym_fn(RTLD_NEXT, "stat64"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_XSTAT_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!___xstat) \ + ___xstat = (int (*)(int, const char *, struct stat *)) dlsym_fn(RTLD_NEXT, "__xstat"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_XSTAT64_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!___xstat64) \ + ___xstat64 = (int (*)(int, const char *, struct stat64 *)) dlsym_fn(RTLD_NEXT, "__xstat64"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + #define LOAD_FOPEN_FUNC() \ do { \ pthread_mutex_lock(&func_mutex); \ @@ -2348,7 +2388,107 @@ int access(const char *pathname, int mode) { return 0; } +int stat(const char *pathname, struct stat *buf) { #ifdef HAVE_OPEN64 + struct stat64 parent; +#else + struct stat parent; +#endif + int ret; + + if (!pathname || !buf) { + errno = EFAULT; + return -1; + } + + if (strcmp(pathname, "/dev/dsp") != 0 && + strcmp(pathname, "/dev/adsp") != 0 && + strcmp(pathname, "/dev/sndstat") != 0 && + strcmp(pathname, "/dev/mixer") != 0) { + debug(DEBUG_LEVEL_VERBOSE, __FILE__": stat(%s)\n", pathname); + LOAD_STAT_FUNC(); + return _stat(pathname, buf); + } + + debug(DEBUG_LEVEL_NORMAL, __FILE__": stat(%s)\n", pathname); + +#ifdef _STAT_VER +#ifdef HAVE_OPEN64 + ret = __xstat64(_STAT_VER, "/dev", &parent); +#else + ret = __xstat(_STAT_VER, "/dev", &parent); +#endif +#else +#ifdef HAVE_OPEN64 + ret = stat64("/dev", &parent); +#else + ret = stat("/dev", &parent); +#endif +#endif + + if (ret) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": unable to stat \"/dev\"\n"); + return -1; + } + + buf->st_dev = parent.st_dev; + buf->st_ino = 0xDEADBEEF; /* FIXME: Can we do this in a safe way? */ + buf->st_mode = S_IFCHR | S_IRUSR | S_IWUSR; + buf->st_nlink = 1; + buf->st_uid = getuid(); + buf->st_gid = getgid(); + buf->st_rdev = 0x0E03; /* FIXME: Linux specific */ + buf->st_size = 0; + buf->st_atime = 1181557705; + buf->st_mtime = 1181557705; + buf->st_ctime = 1181557705; + buf->st_blksize = 1; + buf->st_blocks = 0; + + return 0; +} + +#ifdef HAVE_OPEN64 + +int stat64(const char *pathname, struct stat64 *buf) { + struct stat oldbuf; + int ret; + + if (!pathname || !buf) { + errno = EFAULT; + return -1; + } + + debug(DEBUG_LEVEL_VERBOSE, __FILE__": stat64(%s)\n", pathname); + + if (strcmp(pathname, "/dev/dsp") != 0 && + strcmp(pathname, "/dev/adsp") != 0 && + strcmp(pathname, "/dev/sndstat") != 0 && + strcmp(pathname, "/dev/mixer") != 0) { + LOAD_STAT64_FUNC(); + return _stat64(pathname, buf); + } + + ret = stat(pathname, &oldbuf); + if (ret) + return ret; + + buf->st_dev = oldbuf.st_dev; + buf->st_ino = oldbuf.st_ino; + buf->st_mode = oldbuf.st_mode; + buf->st_nlink = oldbuf.st_nlink; + buf->st_uid = oldbuf.st_uid; + buf->st_gid = oldbuf.st_gid; + buf->st_rdev = oldbuf.st_rdev; + buf->st_size = oldbuf.st_size; + buf->st_atime = oldbuf.st_atime; + buf->st_mtime = oldbuf.st_mtime; + buf->st_ctime = oldbuf.st_ctime; + buf->st_blksize = oldbuf.st_blksize; + buf->st_blocks = oldbuf.st_blocks; + + return 0; +} int open64(const char *filename, int flags, ...) { va_list args; @@ -2374,6 +2514,62 @@ int open64(const char *filename, int flags, ...) { #endif +#ifdef _STAT_VER + +int __xstat(int ver, const char *pathname, struct stat *buf) { + if (!pathname || !buf) { + errno = EFAULT; + return -1; + } + + debug(DEBUG_LEVEL_VERBOSE, __FILE__": __xstat(%s)\n", pathname); + + if (strcmp(pathname, "/dev/dsp") != 0 && + strcmp(pathname, "/dev/adsp") != 0 && + strcmp(pathname, "/dev/sndstat") != 0 && + strcmp(pathname, "/dev/mixer") != 0) { + LOAD_XSTAT_FUNC(); + return ___xstat(ver, pathname, buf); + } + + if (ver != _STAT_VER) { + errno = EINVAL; + return -1; + } + + return stat(pathname, buf); +} + +#ifdef HAVE_OPEN64 + +int __xstat64(int ver, const char *pathname, struct stat64 *buf) { + if (!pathname || !buf) { + errno = EFAULT; + return -1; + } + + debug(DEBUG_LEVEL_VERBOSE, __FILE__": __xstat64(%s)\n", pathname); + + if (strcmp(pathname, "/dev/dsp") != 0 && + strcmp(pathname, "/dev/adsp") != 0 && + strcmp(pathname, "/dev/sndstat") != 0 && + strcmp(pathname, "/dev/mixer") != 0) { + LOAD_XSTAT64_FUNC(); + return ___xstat64(ver, pathname, buf); + } + + if (ver != _STAT_VER) { + errno = EINVAL; + return -1; + } + + return stat64(pathname, buf); +} + +#endif + +#endif + FILE* fopen(const char *filename, const char *mode) { FILE *f = NULL; int fd; -- cgit From 0694d2ae3549ed4e7cb8fca3558fb90ed844fca1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 13 Jun 2007 07:21:57 +0000 Subject: Make sure mixer ioctls work on /dev/dsp aswell. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1473 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 9a2bad44..95fc9ed3 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -2279,11 +2279,12 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_SETDUPLEX: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETDUPLEX\n"); - /* this is a no-op */ - break; + /* this is a no-op */ + break; default: - debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); + /* Mixer ioctls are valid on /dev/dsp aswell */ + return mixer_ioctl(i, request, argp, _errno); inval: *_errno = EINVAL; -- cgit From a67c21f093202f142438689d3f7cfbdf4ea82eea Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Oct 2007 19:13:50 +0000 Subject: merge 'lennart' branch back into trunk. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1971 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 71 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 29 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 95fc9ed3..b48af93c 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -61,6 +61,10 @@ # define SIOCINQ FIONREAD #endif +/* make sure gcc doesn't redefine open and friends as macros */ +#undef open +#undef open64 + typedef enum { FD_INFO_MIXER, FD_INFO_STREAM, @@ -259,9 +263,9 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ static void debug(int level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); -#define DEBUG_LEVEL_ALWAYS 0 -#define DEBUG_LEVEL_NORMAL 1 -#define DEBUG_LEVEL_VERBOSE 2 +#define DEBUG_LEVEL_ALWAYS 0 +#define DEBUG_LEVEL_NORMAL 1 +#define DEBUG_LEVEL_VERBOSE 2 static void debug(int level, const char *format, ...) { va_list ap; @@ -421,7 +425,7 @@ static void fd_info_unref(fd_info *i) { pthread_mutex_lock(&i->mutex); assert(i->ref >= 1); r = --i->ref; - debug(DEBUG_LEVEL_VERBOSE, __FILE__": ref--, now %i\n", i->ref); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": ref--, now %i\n", i->ref); pthread_mutex_unlock(&i->mutex); if (r <= 0) @@ -1395,7 +1399,7 @@ static int sndstat_open(int flags, int *_errno) { if (flags != O_RDONLY #ifdef O_LARGEFILE - && flags != (O_RDONLY|O_LARGEFILE) + && flags != (O_RDONLY|O_LARGEFILE) #endif ) { *_errno = EACCES; @@ -1436,34 +1440,23 @@ fail: return -1; } -int open(const char *filename, int flags, ...) { - va_list args; - mode_t mode = 0; +static int real_open(const char *filename, int flags, mode_t mode) { int r, _errno = 0; debug(DEBUG_LEVEL_VERBOSE, __FILE__": open(%s)\n", filename); - va_start(args, flags); - if (flags & O_CREAT) { - if (sizeof(mode_t) < sizeof(int)) - mode = va_arg(args, int); - else - mode = va_arg(args, mode_t); - } - va_end(args); - if (!function_enter()) { LOAD_OPEN_FUNC(); return _open(filename, flags, mode); } - if (dsp_cloak_enable() && (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0)) { + if (dsp_cloak_enable() && (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0)) r = dsp_open(flags, &_errno); - } else if (mixer_cloak_enable() && strcmp(filename, "/dev/mixer") == 0) { + else if (mixer_cloak_enable() && strcmp(filename, "/dev/mixer") == 0) r = mixer_open(flags, &_errno); - } else if (sndstat_cloak_enable() && strcmp(filename, "/dev/sndstat") == 0) { + else if (sndstat_cloak_enable() && strcmp(filename, "/dev/sndstat") == 0) r = sndstat_open(flags, &_errno); - } else { + else { function_exit(); LOAD_OPEN_FUNC(); return _open(filename, flags, mode); @@ -1477,6 +1470,22 @@ int open(const char *filename, int flags, ...) { return r; } +int open(const char *filename, int flags, ...) { + va_list args; + mode_t mode = 0; + + if (flags & O_CREAT) { + va_start(args, flags); + if (sizeof(mode_t) < sizeof(int)) + mode = va_arg(args, int); + else + mode = va_arg(args, mode_t); + va_end(args); + } + + return real_open(filename, flags, mode); +} + static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { int ret = -1; @@ -2023,9 +2032,9 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) *(int*) argp = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER #ifdef DSP_CAP_MULTI - | DSP_CAP_MULTI + | DSP_CAP_MULTI #endif - ; + ; break; case SNDCTL_DSP_GETODELAY: { @@ -2497,10 +2506,14 @@ int open64(const char *filename, int flags, ...) { debug(DEBUG_LEVEL_VERBOSE, __FILE__": open64(%s)\n", filename); - va_start(args, flags); - if (flags & O_CREAT) - mode = va_arg(args, mode_t); - va_end(args); + if (flags & O_CREAT) { + va_start(args, flags); + if (sizeof(mode_t) < sizeof(int)) + mode = va_arg(args, int); + else + mode = va_arg(args, mode_t); + va_end(args); + } if (strcmp(filename, "/dev/dsp") != 0 && strcmp(filename, "/dev/adsp") != 0 && @@ -2510,7 +2523,7 @@ int open64(const char *filename, int flags, ...) { return _open64(filename, flags, mode); } - return open(filename, flags, mode); + return real_open(filename, flags, mode); } #endif @@ -2602,7 +2615,7 @@ FILE* fopen(const char *filename, const char *mode) { if ((((mode[1] == 'b') || (mode[1] == 't')) && (mode[2] == '+')) || (mode[1] == '+')) m = O_RDWR; - if ((fd = open(filename, m)) < 0) + if ((fd = real_open(filename, m, 0)) < 0) return NULL; if (!(f = fdopen(fd, mode))) { -- cgit From 75e1ebdf772b07949636662d0b9e52189d8a78e7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 15 Feb 2008 11:50:48 +0000 Subject: Improve compatibility with applications which like to pass invalid strings to the libc functions we overwrite, by handing directly to the original function. Patch by Colin Guthrie and Gustavo De Nardin, Closes #227 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2106 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 132 +++++++++++++++++++++++++----------------------------- 1 file changed, 60 insertions(+), 72 deletions(-) (limited to 'src/utils/padsp.c') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index b48af93c..cb57ff8a 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1443,18 +1443,18 @@ fail: static int real_open(const char *filename, int flags, mode_t mode) { int r, _errno = 0; - debug(DEBUG_LEVEL_VERBOSE, __FILE__": open(%s)\n", filename); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": open(%s)\n", filename?filename:"NULL"); if (!function_enter()) { LOAD_OPEN_FUNC(); return _open(filename, flags, mode); } - if (dsp_cloak_enable() && (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0)) + if (filename && dsp_cloak_enable() && (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0)) r = dsp_open(flags, &_errno); - else if (mixer_cloak_enable() && strcmp(filename, "/dev/mixer") == 0) + else if (filename && mixer_cloak_enable() && strcmp(filename, "/dev/mixer") == 0) r = mixer_open(flags, &_errno); - else if (sndstat_cloak_enable() && strcmp(filename, "/dev/sndstat") == 0) + else if (filename && sndstat_cloak_enable() && strcmp(filename, "/dev/sndstat") == 0) r = sndstat_open(flags, &_errno); else { function_exit(); @@ -2371,18 +2371,13 @@ int close(int fd) { int access(const char *pathname, int mode) { - if (!pathname) { - /* Firefox needs this. See #27 */ - errno = EFAULT; - return -1; - } - - debug(DEBUG_LEVEL_VERBOSE, __FILE__": access(%s)\n", pathname); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": access(%s)\n", pathname?pathname:"NULL"); - if (strcmp(pathname, "/dev/dsp") != 0 && - strcmp(pathname, "/dev/adsp") != 0 && - strcmp(pathname, "/dev/sndstat") != 0 && - strcmp(pathname, "/dev/mixer") != 0) { + if (!pathname || + ( strcmp(pathname, "/dev/dsp") != 0 && + strcmp(pathname, "/dev/adsp") != 0 && + strcmp(pathname, "/dev/sndstat") != 0 && + strcmp(pathname, "/dev/mixer") != 0 )) { LOAD_ACCESS_FUNC(); return _access(pathname, mode); } @@ -2406,16 +2401,13 @@ int stat(const char *pathname, struct stat *buf) { #endif int ret; - if (!pathname || !buf) { - errno = EFAULT; - return -1; - } - - if (strcmp(pathname, "/dev/dsp") != 0 && - strcmp(pathname, "/dev/adsp") != 0 && - strcmp(pathname, "/dev/sndstat") != 0 && - strcmp(pathname, "/dev/mixer") != 0) { - debug(DEBUG_LEVEL_VERBOSE, __FILE__": stat(%s)\n", pathname); + if (!pathname || + !buf || + ( strcmp(pathname, "/dev/dsp") != 0 && + strcmp(pathname, "/dev/adsp") != 0 && + strcmp(pathname, "/dev/sndstat") != 0 && + strcmp(pathname, "/dev/mixer") != 0 )) { + debug(DEBUG_LEVEL_VERBOSE, __FILE__": stat(%s)\n", pathname?pathname:"NULL"); LOAD_STAT_FUNC(); return _stat(pathname, buf); } @@ -2464,17 +2456,14 @@ int stat64(const char *pathname, struct stat64 *buf) { struct stat oldbuf; int ret; - if (!pathname || !buf) { - errno = EFAULT; - return -1; - } - - debug(DEBUG_LEVEL_VERBOSE, __FILE__": stat64(%s)\n", pathname); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": stat64(%s)\n", pathname?pathname:"NULL"); - if (strcmp(pathname, "/dev/dsp") != 0 && - strcmp(pathname, "/dev/adsp") != 0 && - strcmp(pathname, "/dev/sndstat") != 0 && - strcmp(pathname, "/dev/mixer") != 0) { + if (!pathname || + !buf || + ( strcmp(pathname, "/dev/dsp") != 0 && + strcmp(pathname, "/dev/adsp") != 0 && + strcmp(pathname, "/dev/sndstat") != 0 && + strcmp(pathname, "/dev/mixer") != 0 )) { LOAD_STAT64_FUNC(); return _stat64(pathname, buf); } @@ -2504,7 +2493,7 @@ int open64(const char *filename, int flags, ...) { va_list args; mode_t mode = 0; - debug(DEBUG_LEVEL_VERBOSE, __FILE__": open64(%s)\n", filename); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": open64(%s)\n", filename?filename:"NULL"); if (flags & O_CREAT) { va_start(args, flags); @@ -2515,10 +2504,11 @@ int open64(const char *filename, int flags, ...) { va_end(args); } - if (strcmp(filename, "/dev/dsp") != 0 && - strcmp(filename, "/dev/adsp") != 0 && - strcmp(filename, "/dev/sndstat") != 0 && - strcmp(filename, "/dev/mixer") != 0) { + if (!filename || + ( strcmp(filename, "/dev/dsp") != 0 && + strcmp(filename, "/dev/adsp") != 0 && + strcmp(filename, "/dev/sndstat") != 0 && + strcmp(filename, "/dev/mixer") != 0 )) { LOAD_OPEN64_FUNC(); return _open64(filename, flags, mode); } @@ -2531,17 +2521,14 @@ int open64(const char *filename, int flags, ...) { #ifdef _STAT_VER int __xstat(int ver, const char *pathname, struct stat *buf) { - if (!pathname || !buf) { - errno = EFAULT; - return -1; - } - - debug(DEBUG_LEVEL_VERBOSE, __FILE__": __xstat(%s)\n", pathname); - - if (strcmp(pathname, "/dev/dsp") != 0 && - strcmp(pathname, "/dev/adsp") != 0 && - strcmp(pathname, "/dev/sndstat") != 0 && - strcmp(pathname, "/dev/mixer") != 0) { + debug(DEBUG_LEVEL_VERBOSE, __FILE__": __xstat(%s)\n", pathname?pathname:"NULL"); + + if (!pathname || + !buf || + ( strcmp(pathname, "/dev/dsp") != 0 && + strcmp(pathname, "/dev/adsp") != 0 && + strcmp(pathname, "/dev/sndstat") != 0 && + strcmp(pathname, "/dev/mixer") != 0 )) { LOAD_XSTAT_FUNC(); return ___xstat(ver, pathname, buf); } @@ -2557,17 +2544,14 @@ int __xstat(int ver, const char *pathname, struct stat *buf) { #ifdef HAVE_OPEN64 int __xstat64(int ver, const char *pathname, struct stat64 *buf) { - if (!pathname || !buf) { - errno = EFAULT; - return -1; - } - - debug(DEBUG_LEVEL_VERBOSE, __FILE__": __xstat64(%s)\n", pathname); - - if (strcmp(pathname, "/dev/dsp") != 0 && - strcmp(pathname, "/dev/adsp") != 0 && - strcmp(pathname, "/dev/sndstat") != 0 && - strcmp(pathname, "/dev/mixer") != 0) { + debug(DEBUG_LEVEL_VERBOSE, __FILE__": __xstat64(%s)\n", pathname?pathname:"NULL"); + + if (!pathname || + !buf || + ( strcmp(pathname, "/dev/dsp") != 0 && + strcmp(pathname, "/dev/adsp") != 0 && + strcmp(pathname, "/dev/sndstat") != 0 && + strcmp(pathname, "/dev/mixer") != 0 )) { LOAD_XSTAT64_FUNC(); return ___xstat64(ver, pathname, buf); } @@ -2589,12 +2573,14 @@ FILE* fopen(const char *filename, const char *mode) { int fd; mode_t m; - debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen(%s)\n", filename); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen(%s)\n", filename?filename:"NULL"); - if (strcmp(filename, "/dev/dsp") != 0 && - strcmp(filename, "/dev/adsp") != 0 && - strcmp(filename, "/dev/sndstat") != 0 && - strcmp(filename, "/dev/mixer") != 0) { + if (!filename || + !mode || + ( strcmp(filename, "/dev/dsp") != 0 && + strcmp(filename, "/dev/adsp") != 0 && + strcmp(filename, "/dev/sndstat") != 0 && + strcmp(filename, "/dev/mixer") != 0 )) { LOAD_FOPEN_FUNC(); return _fopen(filename, mode); } @@ -2630,12 +2616,14 @@ FILE* fopen(const char *filename, const char *mode) { FILE *fopen64(const char *filename, const char *mode) { - debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen64(%s)\n", filename); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen64(%s)\n", filename?filename:"NULL"); - if (strcmp(filename, "/dev/dsp") != 0 && - strcmp(filename, "/dev/adsp") != 0 && - strcmp(filename, "/dev/sndstat") != 0 && - strcmp(filename, "/dev/mixer") != 0) { + if (!filename || + !mode || + ( strcmp(filename, "/dev/dsp") != 0 && + strcmp(filename, "/dev/adsp") != 0 && + strcmp(filename, "/dev/sndstat") != 0 && + strcmp(filename, "/dev/mixer") != 0 )) { LOAD_FOPEN64_FUNC(); return _fopen64(filename, mode); } -- cgit