]> code.delx.au - pulseaudio/blobdiff - src/modules/module-waveout.c
sink-input: Fix underrun_for calculation when resampling.
[pulseaudio] / src / modules / module-waveout.c
index 90d059918a4bf203810c6cb6443387892f0bcb86..53efce9ec920ab028cfb8adb9916bed3e21e6475 100644 (file)
 #include <windows.h>
 #include <mmsystem.h>
 
-#include <pulse/mainloop-api.h>
-
 #include <pulse/xmalloc.h>
 #include <pulse/timeval.h>
-#include <pulse/rtclock.h>
 
 #include <pulsecore/sink.h>
 #include <pulsecore/source.h>
@@ -56,11 +53,11 @@ PA_MODULE_USAGE(
     "record=<enable source?> "
     "playback=<enable sink?> "
     "format=<sample format> "
-    "channels=<number of channels> "
     "rate=<sample rate> "
+    "channels=<number of channels> "
+    "channel_map=<channel map> "
     "fragments=<number of fragments> "
-    "fragment_size=<fragment size> "
-    "channel_map=<channel map>");
+    "fragment_size=<fragment size>");
 
 #define DEFAULT_SINK_NAME "wave_output"
 #define DEFAULT_SOURCE_NAME "wave_input"
@@ -256,20 +253,23 @@ static void thread_func(void *userdata) {
 
     for (;;) {
         int ret;
+        pa_bool_t need_timer = FALSE;
 
-        if (PA_SINK_IS_OPENED(u->sink->thread_info.state) ||
-            PA_SOURCE_IS_OPENED(u->source->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);
 
-            if (PA_SINK_IS_OPENED(u->sink->thread_info.state))
-                do_write(u);
-            if (PA_SOURCE_IS_OPENED(u->source->thread_info.state))
-                do_read(u);
+            do_write(u);
+            need_timer = TRUE;
+        }
+        if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state)) {
+            do_read(u);
+            need_timer = TRUE;
+        }
 
+        if (need_timer)
             pa_rtpoll_set_timer_relative(u->rtpoll, u->poll_timeout);
-        else
+        else
             pa_rtpoll_set_timer_disabled(u->rtpoll);
 
         /* Hmm, nothing to do. Let's sleep */
@@ -400,14 +400,23 @@ static int process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa
 
 static void sink_get_volume_cb(pa_sink *s) {
     struct userdata *u = s->userdata;
+    WAVEOUTCAPS caps;
     DWORD vol;
     pa_volume_t left, right;
 
+    if (waveOutGetDevCaps(u->hwo, &caps, sizeof(caps)) != MMSYSERR_NOERROR)
+        return;
+    if (!(caps.dwSupport & WAVECAPS_VOLUME))
+        return;
+
     if (waveOutGetVolume(u->hwo, &vol) != MMSYSERR_NOERROR)
         return;
 
     left = PA_CLAMP_VOLUME((vol & 0xFFFF) * PA_VOLUME_NORM / WAVEOUT_MAX_VOLUME);
-    right = PA_CLAMP_VOLUME(((vol >> 16) & 0xFFFF) * PA_VOLUME_NORM / WAVEOUT_MAX_VOLUME);
+    if (caps.dwSupport & WAVECAPS_LRVOLUME)
+        right = PA_CLAMP_VOLUME(((vol >> 16) & 0xFFFF) * PA_VOLUME_NORM / WAVEOUT_MAX_VOLUME);
+    else
+        right = left;
 
     /* Windows supports > 2 channels, except for volume control */
     if (s->real_volume.channels > 2)
@@ -420,11 +429,21 @@ static void sink_get_volume_cb(pa_sink *s) {
 
 static void sink_set_volume_cb(pa_sink *s) {
     struct userdata *u = s->userdata;
+    WAVEOUTCAPS caps;
     DWORD vol;
 
-    vol = s->real_volume.values[0] * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM;
-    if (s->real_volume.channels > 1)
-        vol |= (s->real_volume.values[1] * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM) << 16;
+    if (waveOutGetDevCaps(u->hwo, &caps, sizeof(caps)) != MMSYSERR_NOERROR)
+        return;
+    if (!(caps.dwSupport & WAVECAPS_VOLUME))
+        return;
+
+    if (s->real_volume.channels == 2 && caps.dwSupport & WAVECAPS_LRVOLUME) {
+        vol = (s->real_volume.values[0] * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM)
+            | (s->real_volume.values[1] * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM) << 16;
+    } else {
+        vol = (pa_cvolume_avg(&(s->real_volume)) * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM)
+            | (pa_cvolume_avg(&(s->real_volume)) * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM) << 16;
+    }
 
     if (waveOutSetVolume(u->hwo, vol) != MMSYSERR_NOERROR)
         return;
@@ -618,8 +637,8 @@ int pa__init(pa_module *m) {
         pa_sink_new_data_done(&data);
 
         pa_assert(u->sink);
-        u->sink->get_volume = sink_get_volume_cb;
-        u->sink->set_volume = sink_set_volume_cb;
+        pa_sink_set_get_volume_callback(u->sink, sink_get_volume_cb);
+        pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
         u->sink->userdata = u;
         pa_sink_set_description(u->sink, description);
         u->sink->parent.process_msg = process_msg;
@@ -643,6 +662,7 @@ int pa__init(pa_module *m) {
     u->sink_underflow = 1;
 
     u->poll_timeout = pa_bytes_to_usec(u->fragments * u->fragment_size / 10, &ss);
+    pa_log_debug("Poll timeout = %.1f ms", (double) u->poll_timeout / PA_USEC_PER_MSEC);
 
     u->cur_ihdr = 0;
     u->cur_ohdr = 0;