]> code.delx.au - pulseaudio/blobdiff - src/modules/oss/module-oss.c
introduce default channel map in addition to the default sample spec
[pulseaudio] / src / modules / oss / module-oss.c
index 23a325499da569e1c15d8309f73b26d84e844b8d..54d1679f74f9e90f767a988ecfc8478cac658b9a 100644 (file)
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/rtpoll.h>
 
+#if defined(__NetBSD__) && !defined(SNDCTL_DSP_GETODELAY)
+#include <sys/audioio.h>
+#include <sys/syscall.h>
+#endif
+
 #include "oss-util.h"
 #include "module-oss-symdef.h"
 
@@ -121,7 +126,7 @@ struct userdata {
     int mixer_fd;
     int mixer_devmask;
 
-    int nfrags, frag_size;
+    int nfrags, frag_size, orig_frag_size;
 
     pa_bool_t use_mmap;
     unsigned out_mmap_current, in_mmap_current;
@@ -399,13 +404,27 @@ static pa_usec_t io_sink_get_latency(struct userdata *u) {
 
     if (u->use_getodelay) {
         int arg;
-
+#if defined(__NetBSD__) && !defined(SNDCTL_DSP_GETODELAY)
+#if defined(AUDIO_GETBUFINFO)
+        struct audio_info info;
+        if (syscall(SYS_ioctl, u->fd, AUDIO_GETBUFINFO, &info) < 0) {
+            pa_log_info("Device doesn't support AUDIO_GETBUFINFO: %s", pa_cstrerror(errno));
+            u->use_getodelay = 0;
+        } else {
+            arg = info.play.seek + info.blocksize / 2;
+            r = pa_bytes_to_usec((size_t) arg, &u->sink->sample_spec);
+        }
+#else
+        pa_log_info("System doesn't support AUDIO_GETBUFINFO");
+        u->use_getodelay = 0;
+#endif
+#else
         if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) {
             pa_log_info("Device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno));
             u->use_getodelay = 0;
         } else
             r = pa_bytes_to_usec((size_t) arg, &u->sink->sample_spec);
-
+#endif
     }
 
     if (!u->use_getodelay && u->use_getospace) {
@@ -424,7 +443,6 @@ static pa_usec_t io_sink_get_latency(struct userdata *u) {
     return r;
 }
 
-
 static pa_usec_t io_source_get_latency(struct userdata *u) {
     pa_usec_t r = 0;
 
@@ -508,9 +526,6 @@ static int suspend(struct userdata *u) {
     return 0;
 }
 
-static int sink_get_volume(pa_sink *s);
-static int source_get_volume(pa_source *s);
-
 static int unsuspend(struct userdata *u) {
     int m;
     pa_sample_spec ss, *ss_original;
@@ -536,7 +551,7 @@ static int unsuspend(struct userdata *u) {
     }
 
     if (u->nfrags >= 2 && u->frag_size >= 1)
-        if (pa_oss_set_fragments(u->fd, u->nfrags, u->frag_size) < 0) {
+        if (pa_oss_set_fragments(u->fd, u->nfrags, u->orig_frag_size) < 0) {
             pa_log_warn("Resume failed, couldn't set original fragment settings.");
             goto fail;
         }
@@ -602,9 +617,9 @@ static int unsuspend(struct userdata *u) {
     build_pollfd(u);
 
     if (u->sink)
-        sink_get_volume(u->sink);
+        pa_sink_get_volume(u->sink, TRUE);
     if (u->source)
-        source_get_volume(u->source);
+        pa_source_get_volume(u->source, TRUE);
 
     pa_log_info("Resumed successfully...");
 
@@ -681,6 +696,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
 
                     break;
 
+                case PA_SINK_INVALID_STATE:
                 case PA_SINK_UNLINKED:
                 case PA_SINK_INIT:
                     ;
@@ -762,6 +778,7 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off
 
                 case PA_SOURCE_UNLINKED:
                 case PA_SOURCE_INIT:
+                case PA_SOURCE_INVALID_STATE:
                     ;
 
             }
@@ -777,84 +794,76 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off
     return ret;
 }
 
-static int sink_get_volume(pa_sink *s) {
+static void sink_get_volume(pa_sink *s) {
     struct userdata *u;
-    int r;
 
     pa_assert_se(u = s->userdata);
 
     pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
 
     if (u->mixer_devmask & SOUND_MASK_VOLUME)
-        if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->volume)) >= 0)
-            return r;
+        if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->virtual_volume) >= 0)
+            return;
 
     if (u->mixer_devmask & SOUND_MASK_PCM)
-        if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->volume)) >= 0)
-            return r;
+        if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->virtual_volume) >= 0)
+            return;
 
     pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
-    return -1;
 }
 
-static int sink_set_volume(pa_sink *s) {
+static void sink_set_volume(pa_sink *s) {
     struct userdata *u;
-    int r;
 
     pa_assert_se(u = s->userdata);
 
     pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
 
     if (u->mixer_devmask & SOUND_MASK_VOLUME)
-        if ((r = pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->volume)) >= 0)
-            return r;
+        if (pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->virtual_volume) >= 0)
+            return;
 
     if (u->mixer_devmask & SOUND_MASK_PCM)
-        if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->volume)) >= 0)
-            return r;
+        if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->virtual_volume) >= 0)
+            return;
 
     pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
-    return -1;
 }
 
-static int source_get_volume(pa_source *s) {
+static void source_get_volume(pa_source *s) {
     struct userdata *u;
-    int r;
 
     pa_assert_se(u = s->userdata);
 
     pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
 
     if (u->mixer_devmask & SOUND_MASK_IGAIN)
-        if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_IGAIN, &s->sample_spec, &s->volume)) >= 0)
-            return r;
+        if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_IGAIN, &s->sample_spec, &s->virtual_volume) >= 0)
+            return;
 
     if (u->mixer_devmask & SOUND_MASK_RECLEV)
-        if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->volume)) >= 0)
-            return r;
+        if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->virtual_volume) >= 0)
+            return;
 
     pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
-    return -1;
 }
 
-static int source_set_volume(pa_source *s) {
+static void source_set_volume(pa_source *s) {
     struct userdata *u;
-    int r;
 
     pa_assert_se(u = s->userdata);
 
     pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
 
     if (u->mixer_devmask & SOUND_MASK_IGAIN)
-        if ((r = pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->volume)) >= 0)
-            return r;
+        if (pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->virtual_volume) >= 0)
+            return;
 
     if (u->mixer_devmask & SOUND_MASK_RECLEV)
-        if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->volume)) >= 0)
-            return r;
+        if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->virtual_volume) >= 0)
+            return;
 
     pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
-    return -1;
 }
 
 static void thread_func(void *userdata) {
@@ -877,7 +886,7 @@ static void thread_func(void *userdata) {
 
 /*        pa_log("loop");    */
 
-        if (PA_SINK_IS_OPENED(u->sink->thread_info.state))
+        if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state))
             if (u->sink->thread_info.rewind_requested)
                 pa_sink_process_rewind(u->sink, 0);
 
@@ -1144,7 +1153,7 @@ int pa__init(pa_module*m) {
     struct userdata *u = NULL;
     const char *dev;
     int fd = -1;
-    int nfrags, frag_size;
+    int nfrags, orig_frag_size, frag_size;
     int mode, caps;
     pa_bool_t record = TRUE, playback = TRUE, use_mmap = TRUE;
     pa_sample_spec ss;
@@ -1176,6 +1185,7 @@ int pa__init(pa_module*m) {
     mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
 
     ss = m->core->default_sample_spec;
+    map = m->core->default_channel_map;
     if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_OSS) < 0) {
         pa_log("Failed to parse sample specification or channel map");
         goto fail;
@@ -1201,12 +1211,12 @@ int pa__init(pa_module*m) {
 
     if (use_mmap && (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_TRIGGER))) {
         pa_log_info("OSS device not mmap capable, falling back to UNIX read/write mode.");
-        use_mmap = 0;
+        use_mmap = FALSE;
     }
 
     if (use_mmap && mode == O_WRONLY) {
         pa_log_info("Device opened for playback only, cannot do memory mapping, falling back to UNIX write() mode.");
-        use_mmap = 0;
+        use_mmap = FALSE;
     }
 
     if (pa_oss_get_hw_description(dev, hwdesc, sizeof(hwdesc)) >= 0)
@@ -1216,6 +1226,7 @@ int pa__init(pa_module*m) {
 
     pa_log_info("Device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
 
+    orig_frag_size = frag_size;
     if (nfrags >= 2 && frag_size >= 1)
         if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0)
             goto fail;
@@ -1235,6 +1246,7 @@ int pa__init(pa_module*m) {
     m->userdata = u;
     u->fd = fd;
     u->mixer_fd = -1;
+    u->mixer_devmask = 0;
     u->use_getospace = u->use_getispace = TRUE;
     u->use_getodelay = TRUE;
     u->mode = mode;
@@ -1242,6 +1254,7 @@ int pa__init(pa_module*m) {
     u->device_name = pa_xstrdup(dev);
     u->in_nfrags = u->out_nfrags = (uint32_t) (u->nfrags = nfrags);
     u->out_fragment_size = u->in_fragment_size = (uint32_t) (u->frag_size = frag_size);
+    u->orig_frag_size = orig_frag_size;
     u->use_mmap = use_mmap;
     u->rtpoll = pa_rtpoll_new();
     pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
@@ -1383,7 +1396,6 @@ int pa__init(pa_module*m) {
 
     if ((u->mixer_fd = pa_oss_open_mixer_for_device(u->device_name)) >= 0) {
         pa_bool_t do_close = TRUE;
-        u->mixer_devmask = 0;
 
         if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &u->mixer_devmask) < 0)
             pa_log_warn("SOUND_MIXER_READ_DEVMASK failed: %s", pa_cstrerror(errno));
@@ -1394,6 +1406,7 @@ int pa__init(pa_module*m) {
                 u->sink->flags |= PA_SINK_HW_VOLUME_CTRL;
                 u->sink->get_volume = sink_get_volume;
                 u->sink->set_volume = sink_set_volume;
+                u->sink->n_volume_steps = 101;
                 do_close = FALSE;
             }
 
@@ -1402,6 +1415,7 @@ int pa__init(pa_module*m) {
                 u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL;
                 u->source->get_volume = source_get_volume;
                 u->source->set_volume = source_set_volume;
+                u->source->n_volume_steps = 101;
                 do_close = FALSE;
             }
         }
@@ -1409,6 +1423,7 @@ int pa__init(pa_module*m) {
         if (do_close) {
             pa_close(u->mixer_fd);
             u->mixer_fd = -1;
+            u->mixer_devmask = 0;
         }
     }