]> code.delx.au - pulseaudio/blobdiff - src/utils/padsp.c
We need to have a callback when changing volume or we might deadlock.
[pulseaudio] / src / utils / padsp.c
index be935060ebad7660258dd9ed748c9d7bc0fa8d5f..c765b6935030f0632971951e874fb9c64ec3ffdd 100644 (file)
@@ -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.
 ***/
@@ -36,6 +36,7 @@
 #include <pthread.h>
 #include <unistd.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <signal.h>
 
+#ifdef __linux__
 #include <linux/sockios.h>
+#endif
 
-#include <polyp/polypaudio.h>
-#include <polypcore/llist.h>
-#include <polypcore/gccmacro.h>
+#include <pulse/pulseaudio.h>
+#include <pulsecore/llist.h>
+#include <pulsecore/gccmacro.h>
 
 typedef enum {
     FD_INFO_MIXER,
@@ -75,6 +78,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;
@@ -100,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;
 
@@ -392,7 +398,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;
@@ -407,7 +413,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");
 
@@ -557,6 +563,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;
@@ -673,6 +680,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? */
@@ -702,13 +716,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) {
@@ -717,7 +728,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) {
@@ -728,10 +741,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);
     }
 }
 
@@ -750,6 +765,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) {
@@ -760,13 +776,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);
 
@@ -807,7 +820,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)) {
@@ -860,14 +875,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;
@@ -1027,7 +1044,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");
 
@@ -1049,23 +1065,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);
@@ -1262,18 +1278,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 +1298,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;
@@ -1291,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;
@@ -1338,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()) {
@@ -1463,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)));
@@ -1500,8 +1524,8 @@ 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->name, "Polypaudio Virtual OSS", sizeof(mi->name));
+            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;
             pa_threaded_mainloop_unlock(i->mainloop);
@@ -1576,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) {
@@ -1594,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) {
@@ -1618,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 */
@@ -1641,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) {
@@ -1839,7 +1873,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);
@@ -1849,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: {
@@ -1880,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);
 
@@ -1931,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)
@@ -1950,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 {
@@ -1963,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;
             }
 
@@ -1981,10 +2034,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;
     }
@@ -2080,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;
@@ -2102,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;
@@ -2144,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);
@@ -2159,6 +2227,8 @@ FILE *fopen64(const char *filename, const char *mode) {
     return fopen(filename, mode);
 }
 
+#endif
+
 int fclose(FILE *f) {
     fd_info *i;