Index: pulse_stubs.c
===================================================================
--- pulse_stubs.c	(revision 25588)
+++ pulse_stubs.c	(working copy)
@@ -78,9 +78,12 @@
 PROXY_STUB_VOID(pa_stream_set_state_callback,
                 (pa_stream *s, pa_stream_notify_cb_t cb, void *userdata),
                 (s, cb, userdata))
-PROXY_STUB     (pa_stream_flush, pa_operation*,
+PROXY_STUB     (pa_stream_drain, pa_operation*,
                 (pa_stream *s, pa_stream_success_cb_t cb, void *userdata),
                 (s, cb, userdata))
+PROXY_STUB     (pa_stream_trigger, pa_operation*,
+                (pa_stream *s, pa_stream_success_cb_t cb, void *userdata),
+		(s, cb, userdata))
 PROXY_STUB     (pa_stream_new, pa_stream*,
                 (pa_context *c, const char *name, const pa_sample_spec *ss,
                  const pa_channel_map *map),
@@ -97,9 +100,6 @@
 PROXY_STUB     (pa_stream_drop, int,
                 (pa_stream *p),
                 (p))
-PROXY_STUB     (pa_stream_trigger, pa_operation*,
-                (pa_stream *s, pa_stream_success_cb_t cb, void *userdata),
-                (s, cb, userdata))
 PROXY_STUB     (pa_stream_writable_size, size_t,
                 (pa_stream *p),
                 (p))
@@ -155,6 +155,9 @@
 PROXY_STUB     (pa_bytes_per_second, size_t,
                 (const pa_sample_spec *spec),
                 (spec))
+PROXY_STUB     (pa_frame_size, size_t,
+                (const pa_sample_spec *spec),
+                (spec))
 PROXY_STUB     (pa_sample_format_to_string, const char*,
                 (pa_sample_format_t f),
                 (f))
@@ -167,9 +170,15 @@
 PROXY_STUB_VOID(pa_operation_unref,
                 (pa_operation *o),
                 (o))
+PROXY_STUB     (pa_operation_get_state, pa_operation_state_t,
+                (pa_operation *o),
+		(o))
 PROXY_STUB     (pa_strerror, const char*,
                 (int error),
                 (error))
+PROXY_STUB     (pa_stream_readable_size, size_t,
+                (pa_stream *p),
+		(p))
 
 
 typedef struct
@@ -190,13 +199,13 @@
     ELEMENT(pa_stream_unref),
     ELEMENT(pa_stream_get_state),
     ELEMENT(pa_stream_set_state_callback),
-    ELEMENT(pa_stream_flush),
+    ELEMENT(pa_stream_drain),
+    ELEMENT(pa_stream_trigger),
     ELEMENT(pa_stream_new),
     ELEMENT(pa_stream_get_buffer_attr),
     ELEMENT(pa_stream_peek),
     ELEMENT(pa_stream_cork),
     ELEMENT(pa_stream_drop),
-    ELEMENT(pa_stream_trigger),
     ELEMENT(pa_stream_writable_size),
     ELEMENT(pa_context_connect),
     ELEMENT(pa_context_disconnect),
@@ -215,11 +224,14 @@
     ELEMENT(pa_threaded_mainloop_start),
     ELEMENT(pa_threaded_mainloop_lock),
     ELEMENT(pa_bytes_per_second),
+    ELEMENT(pa_frame_size),
     ELEMENT(pa_sample_format_to_string),
     ELEMENT(pa_sample_spec_valid),
     ELEMENT(pa_channel_map_init_auto),
     ELEMENT(pa_operation_unref),
+    ELEMENT(pa_operation_get_state),
     ELEMENT(pa_strerror),
+    ELEMENT(pa_stream_readable_size)
 };
 #undef ELEMENT
 
Index: pulseaudio.c
===================================================================
--- pulseaudio.c	(revision 25588)
+++ pulseaudio.c	(working copy)
@@ -19,7 +19,6 @@
  * additional information or have any questions.
  */
 
-
 /*******************************************************************************
 *   Header Files                                                               *
 *******************************************************************************/
@@ -46,55 +45,31 @@
 static struct pa_threaded_mainloop *g_pMainLoop;
 static struct pa_context           *g_pContext;
 
-typedef struct PulseVoice
-{
+typedef struct PulseVoice {
     HWVoiceOut  hw;
     void       *pPCMBuf;
-    pa_stream  *pStream;
+    pa_stream  *stream;
+    pa_sample_spec ss;
+    pa_buffer_attr ba;
     int         fOpSuccess;
     unsigned    cErrors;
+    const void  *peek_buffer;
+    size_t      peek_buffer_length;
+    size_t      peek_buffer_offset;
 } PulseVoice;
 
-static struct
-{
+/* The desired max buffer size in milliseconds. The desired latency will be
+ * calculated to be 1/10 of the value */
+static struct {
     int         buffer_msecs_out;
     int         buffer_msecs_in;
-} conf
-=
-{
-    INIT_FIELD (.buffer_msecs_out = ) 100,
-    INIT_FIELD (.buffer_msecs_in  = ) 100,
+} conf = {
+    INIT_FIELD (.buffer_msecs_out = ) 300,
+    INIT_FIELD (.buffer_msecs_in  = ) 300,
 };
 
-struct pulse_params_req
-{
-    int                 freq;
-    pa_sample_format_t  pa_format;
-    int                 nchannels;
-};
-
-struct pulse_params_obt
-{
-    int                 freq;
-    pa_sample_format_t  pa_format;
-    int                 nchannels;
-    unsigned long       buffer_size;
-};
-
-static void pulse_check_fatal (PulseVoice *pulse, int rc)
-{
-    if (rc == PA_ERR_CONNECTIONTERMINATED)
-    {
-        /* XXX runtime warning */
-        LogRel(("Pulse: Audio input/output stopped!\n"));
-        pulse->cErrors = MAX_LOG_REL_ERRORS;
-    }
-}
-
-static pa_sample_format_t aud_to_pulsefmt (audfmt_e fmt)
-{
-    switch (fmt)
-    {
+static pa_sample_format_t aud_to_pulsefmt (audfmt_e fmt) {
+    switch (fmt) {
         case AUD_FMT_U8:
             return PA_SAMPLE_U8;
 
@@ -113,10 +88,8 @@
 }
 
 
-static int pulse_to_audfmt (pa_sample_format_t pulsefmt, audfmt_e *fmt, int *endianess)
-{
-    switch (pulsefmt)
-    {
+static int pulse_to_audfmt (pa_sample_format_t pulsefmt, audfmt_e *fmt, int *endianess) {
+    switch (pulsefmt) {
         case PA_SAMPLE_U8:
             *endianess = 0;
             *fmt = AUD_FMT_U8;
@@ -152,24 +125,27 @@
     return 0;
 }
 
-static void context_state_callback(pa_context *c, void *userdata)
-{
-    switch (pa_context_get_state(c))
-    {
-        case PA_CONTEXT_READY:
+static void context_state_callback(pa_context *c, void *userdata) {
+    PulseVoice *pulse = (PulseVoice *)userdata;
+    switch (pa_context_get_state(c)) {
         case PA_CONTEXT_TERMINATED:
+        case PA_CONTEXT_READY:
+	    pa_threaded_mainloop_signal(g_pMainLoop, 0);
+	    break;
+
         case PA_CONTEXT_FAILED:
+            LogRel(("Pulse: Audio input/output stopped!\n"));
+            pulse->cErrors = MAX_LOG_REL_ERRORS;
             pa_threaded_mainloop_signal(g_pMainLoop, 0);
             break;
+
         default:
             break;
     }
 }
 
-static void stream_state_callback(pa_stream *s, void *userdata)
-{
-    switch (pa_stream_get_state(s))
-    {
+static void stream_state_callback(pa_stream *s, void *userdata) {
+    switch (pa_stream_get_state(s)) {
         case PA_STREAM_READY:
         case PA_STREAM_FAILED:
         case PA_STREAM_TERMINATED:
@@ -180,88 +156,52 @@
     }
 }
 
-static void stream_latency_update_callback(pa_stream *s, void *userdata)
+static int pulse_open (int fIn, pa_stream **stream, pa_sample_spec *ss, pa_buffer_attr *ba)
 {
-    pa_threaded_mainloop_signal(g_pMainLoop, 0);
-}
+    const pa_buffer_attr    *ba_obtained;
+    char        achPCMName[64];
+    const char  *stream_name = audio_get_stream_name();
 
-static int pulse_open (int fIn, struct pulse_params_req *req,
-                       struct pulse_params_obt *obt, pa_stream **ppStream)
-{
-    pa_sample_spec        sspec;
-    pa_channel_map        cmap;
-    pa_stream            *pStream = NULL;
-    pa_buffer_attr        bufAttr;
-    const pa_buffer_attr *pBufAttr;
-    const pa_sample_spec *pSampSpec;
-    char                  achPCMName[64];
-    pa_stream_flags_t     flags;
-    int                   ms = fIn ? conf.buffer_msecs_in : conf.buffer_msecs_out;
-    const char           *stream_name = audio_get_stream_name();
-
     RTStrPrintf(achPCMName, sizeof(achPCMName), "%.32s%s%s%s",
                 stream_name ? stream_name : "",
                 stream_name ? " (" : "",
                 fIn ? "pcm_in" : "pcm_out",
                 stream_name ? ")" : "");
-    sspec.rate     = req->freq;
-    sspec.channels = req->nchannels;
-    sspec.format   = req->pa_format;
 
     LogRel(("Pulse: open %s rate=%dHz channels=%d format=%s\n",
-                fIn ? "PCM_IN" : "PCM_OUT", req->freq, req->nchannels,
-                pa_sample_format_to_string(req->pa_format)));
+                fIn ? "PCM_IN" : "PCM_OUT", ss->rate, ss->channels,
+                pa_sample_format_to_string(ss->format)));
 
-    if (!pa_sample_spec_valid(&sspec))
-    {
+    if (!pa_sample_spec_valid(ss)) {
         LogRel(("Pulse: Unsupported sample specification\n"));
         goto fail;
     }
 
-    pa_channel_map_init_auto(&cmap, sspec.channels, PA_CHANNEL_MAP_ALSA);
-
-#if 0
-    pa_cvolume_reset(&volume, sspec.channels);
-#endif
-
     pa_threaded_mainloop_lock(g_pMainLoop);
 
-    if (!(pStream = pa_stream_new(g_pContext, achPCMName, &sspec, &cmap)))
-    {
+    if (!(*stream = pa_stream_new(g_pContext, achPCMName, ss, NULL))) {
         LogRel(("Pulse: Cannot create stream %s\n", achPCMName));
         goto unlock_and_fail;
     }
 
-    pSampSpec      = pa_stream_get_sample_spec(pStream);
-    obt->pa_format = pSampSpec->format;
-    obt->nchannels = pSampSpec->channels;
-    obt->freq      = pSampSpec->rate;
+    pa_stream_set_state_callback(*stream, stream_state_callback, NULL);
 
-    pa_stream_set_state_callback(pStream, stream_state_callback, NULL);
-    pa_stream_set_latency_update_callback(pStream, stream_latency_update_callback, NULL);
+    if (fIn) {
+        LogRel(("Pulse: Requested record buffer attributes maxlength=%d fragsize=%d\n",
+                ba->maxlength, ba->fragsize));
 
-    memset(&bufAttr, 0, sizeof(bufAttr));
-    bufAttr.tlength   = (pa_bytes_per_second(pSampSpec) * ms) / 1000;
-    bufAttr.maxlength = (bufAttr.tlength*3) / 2;
-    bufAttr.minreq    = pa_bytes_per_second(pSampSpec) / 100;    /* 10ms */
-    bufAttr.prebuf    = bufAttr.tlength - bufAttr.minreq;
-    bufAttr.fragsize  = pa_bytes_per_second(pSampSpec) / 100;    /* 10ms */
-
-    flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
-    if (fIn)
-    {
-        if (pa_stream_connect_record(pStream, /*dev=*/NULL, &bufAttr, flags) < 0)
-        {
-            LogRel(("Pulse: Cannot connect record stream : %s\n",
+        if (pa_stream_connect_record(*stream, /*channel map=*/NULL, ba, /*flags=*/0) < 0) {
+            LogRel(("Pulse: Cannot connect record stream: %s\n",
                     pa_strerror(pa_context_errno(g_pContext))));
             goto disconnect_unlock_and_fail;
         }
-    }
-    else
-    {
-        if (pa_stream_connect_playback(pStream, /*dev=*/NULL, &bufAttr, flags,
-                                       NULL, NULL) < 0)
-        {
+    } else {
+        LogRel(("Pulse: Requested playback buffer attributes tlength=%d maxlength=%d prebuf=%d minreq=%d\n",
+                ba->tlength, ba->maxlength, ba->prebuf, ba->minreq));
+
+        if (pa_stream_connect_playback(*stream, /*channel map=*/NULL, ba,
+                                       PA_STREAM_ADJUST_LATENCY | PA_STREAM_START_CORKED,
+                                       /*cvolume=*/NULL, /*sync stream=*/NULL) < 0) {
             LogRel(("Pulse: Cannot connect playback stream: %s\n",
                     pa_strerror(pa_context_errno(g_pContext))));
             goto disconnect_unlock_and_fail;
@@ -269,103 +209,101 @@
     }
 
     /* Wait until the stream is ready */
-    for (;;)
-    {
+    for (;;) {
         pa_stream_state_t sstate;
         pa_threaded_mainloop_wait(g_pMainLoop);
-        sstate = pa_stream_get_state(pStream);
+
+        sstate = pa_stream_get_state(*stream);
         if (sstate == PA_STREAM_READY)
             break;
-        else if (sstate == PA_STREAM_FAILED || sstate == PA_STREAM_TERMINATED)
-        {
+        else if (sstate == PA_STREAM_FAILED || sstate == PA_STREAM_TERMINATED) {
             LogRel(("Pulse: Failed to initialize stream (state %d)\n", sstate));
             goto disconnect_unlock_and_fail;
         }
     }
 
-    pBufAttr = pa_stream_get_buffer_attr(pStream);
-    obt->buffer_size = pBufAttr->maxlength;
+    ba_obtained = pa_stream_get_buffer_attr(*stream);
+    memcpy(ba, ba_obtained, sizeof(pa_buffer_attr));
 
-    pa_threaded_mainloop_unlock(g_pMainLoop);
+    LogRel(("Pulse: Obtained Buffer Attr tlength=%d maxlength=%d prebuf=%d minreq=%d fragsize=%d\n",
+            ba->tlength, ba->maxlength, ba->prebuf, ba->minreq, ba->fragsize));
 
-    LogRel(("Pulse: buffer settings: max=%d tlength=%d prebuf=%d minreq=%d\n",
-            pBufAttr->maxlength, pBufAttr->tlength, pBufAttr->prebuf, pBufAttr->minreq));
-
-    *ppStream = pStream;
+    pa_threaded_mainloop_unlock(g_pMainLoop);
     return 0;
 
 disconnect_unlock_and_fail:
-    pa_stream_disconnect(pStream);
+    pa_stream_disconnect(*stream);
 
 unlock_and_fail:
     pa_threaded_mainloop_unlock(g_pMainLoop);
 
 fail:
-    if (pStream)
-        pa_stream_unref(pStream);
+    if (*stream)
+        pa_stream_unref(*stream);
 
-    *ppStream = NULL;
+    *stream = NULL;
     return -1;
 }
 
-static int pulse_init_out (HWVoiceOut *hw, audsettings_t *as)
-{
+static int pulse_init_out (HWVoiceOut *hw, audsettings_t *as) {
     PulseVoice *pulse = (PulseVoice *) hw;
-    struct pulse_params_req req;
-    struct pulse_params_obt obt;
-    audfmt_e effective_fmt;
-    int endianness;
     audsettings_t obt_as;
+    int	tlength;
 
-    req.pa_format   = aud_to_pulsefmt (as->fmt);
-    req.freq        = as->freq;
-    req.nchannels   = as->nchannels;
+    pulse->ss.format    = aud_to_pulsefmt (as->fmt);
+    pulse->ss.rate      = as->freq;
+    pulse->ss.channels  = as->nchannels;
 
-    if (pulse_open (/*fIn=*/0, &req, &obt, &pulse->pStream))
+    pulse->ba.tlength   = (pa_bytes_per_second(&pulse->ss) * conf.buffer_msecs_out) / 10000; /* A Tenth of the buffer size */
+    pulse->ba.maxlength = (pa_bytes_per_second(&pulse->ss) * conf.buffer_msecs_out) / 1000;
+    pulse->ba.prebuf    = -1; /* Same as tlength */
+    pulse->ba.minreq    = -1; /* Pulse should set something sensible for minreq on it's own */
+
+    /* Notice that the struct ba is updated to the obtained values after this call */
+    if (pulse_open (0, &pulse->stream, &pulse->ss, &pulse->ba))
         return -1;
 
-    if (pulse_to_audfmt (obt.pa_format, &effective_fmt, &endianness))
-    {
-        LogRel(("Pulse: Cannot find audio format %d\n", obt.pa_format));
+    if (pulse_to_audfmt (pulse->ss.format, &obt_as.fmt, &obt_as.endianness)) {
+        LogRel(("Pulse: Cannot find audio format %d\n", pulse->ss.format));
         return -1;
     }
 
-    obt_as.freq       = obt.freq;
-    obt_as.nchannels  = obt.nchannels;
-    obt_as.fmt        = effective_fmt;
-    obt_as.endianness = endianness;
+    obt_as.freq       = pulse->ss.rate;
+    obt_as.nchannels  = pulse->ss.channels;
 
     audio_pcm_init_info (&hw->info, &obt_as);
-    hw->samples = obt.buffer_size >> hw->info.shift;
+    hw->samples = audio_MIN(pulse->ba.tlength * 10, pulse->ba.maxlength);
 
-    pulse->pPCMBuf = RTMemAllocZ(obt.buffer_size);
-    if (!pulse->pPCMBuf)
-    {
-        LogRel(("Pulse: Could not allocate DAC buffer of %d bytes\n", obt.buffer_size));
+    pulse->pPCMBuf = RTMemAllocZ(hw->samples);
+    if (!pulse->pPCMBuf) {
+        LogRel(("Pulse: Could not allocate DAC buffer of %d bytes\n", hw->samples));
         return -1;
     }
 
+    /* Convert from bytes to frames (aka samples) */
+    hw->samples >>= hw->info.shift;
+
     return 0;
 }
 
-static void pulse_fini_out (HWVoiceOut *hw)
-{
+static void pulse_fini_out (HWVoiceOut *hw) {
     PulseVoice *pulse = (PulseVoice *)hw;
-    if (pulse->pStream)
-    {
-        pa_stream_disconnect(pulse->pStream);
-        pa_stream_unref(pulse->pStream);
-        pulse->pStream = NULL;
+
+    if (pulse->stream) {
+        pa_threaded_mainloop_lock(g_pMainLoop);
+        pa_stream_disconnect(pulse->stream);
+        pa_stream_unref(pulse->stream);
+        pa_threaded_mainloop_unlock(g_pMainLoop);
+        pulse->stream = NULL;
     }
-    if (pulse->pPCMBuf)
-    {
+
+    if (pulse->pPCMBuf) {
         RTMemFree (pulse->pPCMBuf);
         pulse->pPCMBuf = NULL;
     }
 }
 
-static int pulse_run_out (HWVoiceOut *hw)
-{
+static int pulse_run_out (HWVoiceOut *hw) {
     PulseVoice *pulse = (PulseVoice *) hw;
     int          csLive, csDecr = 0, csSamples, csToWrite, csAvail;
     size_t       cbAvail, cbToWrite;
@@ -373,21 +311,16 @@
     st_sample_t *psSrc;
 
     csLive = audio_pcm_hw_get_live_out (hw);
-    if (!csLive)
-        return 0;
+    if (!csLive) return 0;
 
     pa_threaded_mainloop_lock(g_pMainLoop);
 
-    cbAvail = pa_stream_writable_size (pulse->pStream);
-    if (cbAvail == (size_t)-1)
-    {
-        if (pulse->cErrors < MAX_LOG_REL_ERRORS)
-        {
+    cbAvail = pa_stream_writable_size (pulse->stream);
+    if (cbAvail == (size_t)-1) {
+        if (pulse->cErrors < MAX_LOG_REL_ERRORS) {
             int rc = pa_context_errno(g_pContext);
             pulse->cErrors++;
-            LogRel(("Pulse: Failed to determine the writable size: %s\n",
-                     pa_strerror(rc)));
-            pulse_check_fatal(pulse, rc);
+            LogRel(("Pulse: Failed to determine the writable size: %s\n", pa_strerror(rc)));
         }
         goto unlock_and_exit;
     }
@@ -396,8 +329,7 @@
     csDecr    = audio_MIN (csLive, csAvail);
     csSamples = csDecr;
 
-    while (csSamples)
-    {
+    while (csSamples) {
         /* split request at the end of our samples buffer */
         csToWrite = audio_MIN (csSamples, hw->samples - hw->rpos);
         cbToWrite = csToWrite << hw->info.shift;
@@ -406,7 +338,7 @@
 
         hw->clip (pu8Dst, psSrc, csToWrite);
 
-        if (pa_stream_write (pulse->pStream, pu8Dst, cbToWrite,
+        if (pa_stream_write (pulse->stream, pu8Dst, cbToWrite,
                              /*cleanup_callback=*/NULL, 0, PA_SEEK_RELATIVE) < 0)
         {
             LogRel(("Pulse: Failed to write %d samples: %s\n",
@@ -423,81 +355,78 @@
     return csDecr;
 }
 
-static int pulse_write (SWVoiceOut *sw, void *buf, int len)
-{
+static int pulse_write (SWVoiceOut *sw, void *buf, int len) {
     return audio_pcm_sw_write (sw, buf, len);
 }
 
-static void stream_success_callback(pa_stream *pStream, int success, void *userdata)
-{
+static void stream_success_callback(pa_stream *stream, int success, void *userdata) {
     PulseVoice *pulse = (PulseVoice *) userdata;
     pulse->fOpSuccess = success;
     pa_threaded_mainloop_signal(g_pMainLoop, 0);
 }
 
-typedef enum
-{
-    Unpause  = 0,
-    Pause    = 1,
-    Flush    = 2,
-    Trigger  = 3
+typedef enum {
+    unpause,
+    pause,
+    trigger,
+    drain
 } pulse_cmd_t;
 
-static int pulse_ctrl (HWVoiceOut *hw, pulse_cmd_t cmd)
-{
-    PulseVoice *pulse = (PulseVoice *) hw;
+static int pulse_ctrl (PulseVoice *pulse, pulse_cmd_t cmd) {
     pa_operation *op = NULL;
+    char *cmd_str = cmd == unpause ? "unpause" :
+                    cmd == pause ? "pause" :
+		    cmd == trigger ? "trigger" :
+		    cmd == drain ? "drain" : NULL;
 
-    if (!pulse->pStream)
+    if (!pulse->stream)
         return 0;
 
+    LogRel(("Pulse: ctrl cmd=%s\n", cmd_str));
+
     pa_threaded_mainloop_lock(g_pMainLoop);
-    switch (cmd)
-    {
-        case Pause:
-            op = pa_stream_cork(pulse->pStream, 1, stream_success_callback, pulse);
+    switch (cmd) {
+        case pause:
+            op = pa_stream_cork(pulse->stream, 1, stream_success_callback, pulse);
             break;
-        case Unpause:
-            op = pa_stream_cork(pulse->pStream, 0, stream_success_callback, pulse);
+        case unpause:
+            op = pa_stream_cork(pulse->stream, 0, stream_success_callback, pulse);
             break;
-        case Flush:
-            op = pa_stream_flush(pulse->pStream, stream_success_callback, pulse);
+        case drain:
+            op = pa_stream_drain(pulse->stream, stream_success_callback, pulse);
             break;
-        case Trigger:
-            op = pa_stream_trigger(pulse->pStream, stream_success_callback, pulse);
-            break;
+        case trigger:
+            op = pa_stream_trigger(pulse->stream, stream_success_callback, pulse);
+	    break;
         default:
             goto unlock_and_exit;
     }
-    if (!op)
-    {
-        if (pulse->cErrors < MAX_LOG_REL_ERRORS)
-        {
+    if (!op) {
+        if (pulse->cErrors < MAX_LOG_REL_ERRORS) {
             int rc = pa_context_errno(g_pContext);
             pulse->cErrors++;
-            LogRel(("Pulse: Failed ctrl cmd=%d to stream: %s\n",
-                    cmd, pa_strerror(pa_context_errno(g_pContext))));
-            pulse_check_fatal(pulse, rc);
+            LogRel(("Pulse: Failed ctrl cmd=%s to stream: %s\n", cmd_str, pa_strerror(pa_context_errno(g_pContext))));
         }
-    }
-    else
+    } else {
+        while (pa_operation_get_state(op) == PA_OPERATION_RUNNING)
+            pa_threaded_mainloop_wait(g_pMainLoop);
         pa_operation_unref(op);
+    }
 
 unlock_and_exit:
     pa_threaded_mainloop_unlock(g_pMainLoop);
     return 0;
 }
 
-static int pulse_ctl_out (HWVoiceOut *hw, int cmd, ...)
-{
-    switch (cmd)
-    {
+static int pulse_ctl_out (HWVoiceOut *hw, int cmd, ...) {
+    switch (cmd) {
         case VOICE_ENABLE:
-            pulse_ctrl(hw, Unpause);
-            pulse_ctrl(hw, Trigger);
+            pulse_ctrl((PulseVoice *)hw, unpause);
             break;
         case VOICE_DISABLE:
-            pulse_ctrl(hw, Flush);
+            pulse_ctrl((PulseVoice *)hw, trigger);
+            pulse_ctrl((PulseVoice *)hw, drain);
+	    pulse_ctrl((PulseVoice *)hw, pause);
             break;
         default:
             return -1;
@@ -505,142 +434,160 @@
     return 0;
 }
 
-static int pulse_init_in (HWVoiceIn *hw, audsettings_t *as)
-{
+static int pulse_init_in (HWVoiceIn *hw, audsettings_t *as) {
     PulseVoice *pulse = (PulseVoice *) hw;
-    struct pulse_params_req req;
-    struct pulse_params_obt obt;
-    audfmt_e effective_fmt;
-    int endianness;
     audsettings_t obt_as;
 
-    req.pa_format   = aud_to_pulsefmt (as->fmt);
-    req.freq        = as->freq;
-    req.nchannels   = as->nchannels;
+    pulse->ss.format   = aud_to_pulsefmt (as->fmt);
+    pulse->ss.rate     = as->freq;
+    pulse->ss.channels = as->nchannels;
 
-    if (pulse_open (/*fIn=*/1, &req, &obt, &pulse->pStream))
-        return -1;
+    pulse->ba.fragsize = (pa_bytes_per_second(&pulse->ss) * conf.buffer_msecs_in) / 10000; /* one tenth */
+    pulse->ba.maxlength = (pa_bytes_per_second(&pulse->ss) * conf.buffer_msecs_in) / 1000;
+    /* Other memebers of pa_buffer_attr are ignored for record streams */
 
-    if (pulse_to_audfmt (obt.pa_format, &effective_fmt, &endianness))
-    {
-        LogRel(("Pulse: Cannot find audio format %d\n", obt.pa_format));
+    if (pulse_open (1, &pulse->stream, &pulse->ss, &pulse->ba)) return -1;
+
+    if (pulse_to_audfmt (pulse->ss.format, &obt_as.fmt, &obt_as.endianness)) {
+        LogRel(("Pulse: Cannot find audio format %d\n", pulse->ss.format));
         return -1;
     }
 
-    obt_as.freq       = obt.freq;
-    obt_as.nchannels  = obt.nchannels;
-    obt_as.fmt        = effective_fmt;
-    obt_as.endianness = endianness;
-
+    obt_as.freq       = pulse->ss.rate;
+    obt_as.nchannels  = pulse->ss.channels;
     audio_pcm_init_info (&hw->info, &obt_as);
+    hw->samples = audio_MIN(pulse->ba.fragsize * 10, pulse->ba.maxlength) >> hw->info.shift;
+    pulse->peek_buffer = NULL;
 
-    /* pcm_in: reserve twice as the maximum buffer length because of peek()/drop(). */
-    hw->samples = 2 * (obt.buffer_size >> hw->info.shift);
-
-    /* no buffer for input */
-    pulse->pPCMBuf = NULL;
-
     return 0;
 }
 
-static void pulse_fini_in (HWVoiceIn *hw)
-{
+static void pulse_fini_in (HWVoiceIn *hw) {
     PulseVoice *pulse = (PulseVoice *)hw;
-    if (pulse->pStream)
-    {
-        pa_stream_disconnect(pulse->pStream);
-        pa_stream_unref(pulse->pStream);
-        pulse->pStream = NULL;
+
+    if (pulse->stream) {
+        pa_threaded_mainloop_lock(g_pMainLoop);
+        pa_stream_disconnect(pulse->stream);
+        pa_stream_unref(pulse->stream);
+        pa_threaded_mainloop_unlock(g_pMainLoop);
+        pulse->stream = NULL;
     }
-    if (pulse->pPCMBuf)
-    {
-        RTMemFree (pulse->pPCMBuf);
-        pulse->pPCMBuf = NULL;
-    }
 }
 
-static int pulse_run_in (HWVoiceIn *hw)
-{
+static int pulse_run_in (HWVoiceIn *hw) {
     PulseVoice *pulse = (PulseVoice *) hw;
-    int    csDead, csDecr = 0, csSamples, csRead, csAvail;
-    size_t cbAvail;
-    const void  *pu8Src;
-    st_sample_t *psDst;
+    const int hwshift = hw->info.shift;
+    int     read_frames = 0;    /* Total frames which have been read this call */
+    int     avail_frames;       /* Total frames available from pulse at start of call */ 
+    int     to_read;            /* The largest amount we want/can get this call */
+    int     to_peek;            /* The largest amount we want/can get this peek */
 
-    csDead = hw->samples - audio_pcm_hw_get_live_in (hw);
+    /* We should only call pa_stream_readable_size() once and trust the first value */
+    pa_threaded_mainloop_lock(g_pMainLoop); 
+    avail_frames = pa_stream_readable_size(pulse->stream) >> hwshift;
+    pa_threaded_mainloop_unlock(g_pMainLoop);
+    
+    /* If the buffer was not dropped last call, add what remains */
+    if (pulse->peek_buffer)
+        avail_frames += (pulse->peek_buffer_length - pulse->peek_buffer_offset) >> hwshift;
 
-    if (!csDead)
-        return 0; /* no buffer available */
+    to_read = audio_MIN(avail_frames, hw->samples - audio_pcm_hw_get_live_in(hw));
+    for (; to_read; to_read -= to_peek) {
 
-    pa_threaded_mainloop_lock(g_pMainLoop);
+        /* If there is no data, do another peek */
+        if (!pulse->peek_buffer) {
+            pa_threaded_mainloop_lock(g_pMainLoop);
+            pa_stream_peek(pulse->stream, &pulse->peek_buffer, &pulse->peek_buffer_length);
+            pa_threaded_mainloop_unlock(g_pMainLoop);
+            pulse->peek_buffer_offset = 0;
+            if (!pulse->peek_buffer_length) break;
+        }
 
-    if (pa_stream_peek(pulse->pStream, &pu8Src, &cbAvail) < 0)
-    {
-        LogRel(("Pulse: Peek failed: %s\n",
-                pa_strerror(pa_context_errno(g_pContext))));
-        goto unlock_and_exit;
-    }
-    if (!pu8Src)
-        goto unlock_and_exit;
+        to_peek = audio_MIN((signed)(pulse->peek_buffer_length - pulse->peek_buffer_offset) >> hwshift, to_read);
 
-    csAvail = cbAvail >> hw->info.shift;
-    csDecr  = audio_MIN (csDead, csAvail);
+        /* Check for wrapping around the buffer end */
+        if (to_peek + hw->wpos > hw->samples) {
+            int delta = hw->samples - hw->wpos;
 
-    csSamples = csDecr;
+            hw->conv(hw->conv_buf + hw->wpos,
+                     (uint8_t*)pulse->peek_buffer + pulse->peek_buffer_offset,
+                     delta,
+                     &nominal_volume);
 
-    while (csSamples)
-    {
-        /* split request at the end of our samples buffer */
-        psDst      = hw->conv_buf + hw->wpos;
-        csRead     = audio_MIN (csSamples, hw->samples - hw->wpos);
-        hw->conv (psDst, pu8Src, csRead, &nominal_volume);
-        hw->wpos   = (hw->wpos + csRead) % hw->samples;
-        csSamples -= csRead;
-        pu8Src     = (const void*)((uint8_t*)pu8Src + (csRead << hw->info.shift));
+            hw->conv(hw->conv_buf,
+                     (uint8_t*)pulse->peek_buffer + pulse->peek_buffer_offset + (delta << hwshift),
+                     to_peek - delta,
+                     &nominal_volume);
+        } else {
+            hw->conv(hw->conv_buf + hw->wpos,
+                     (uint8_t*)pulse->peek_buffer + pulse->peek_buffer_offset,
+                     to_peek,
+                     &nominal_volume);
+        }
+        
+        read_frames += to_peek;
+        hw->wpos = (hw->wpos + to_peek) % hw->samples;
+        pulse->peek_buffer_offset += to_peek << hwshift;
+
+        /* If the buffer is done, drop it */
+        if (pulse->peek_buffer_offset == pulse->peek_buffer_length) {
+            pa_threaded_mainloop_lock(g_pMainLoop);            
+            pa_stream_drop(pulse->stream);
+            pa_threaded_mainloop_unlock(g_pMainLoop);            
+            pulse->peek_buffer = NULL;
+        }
     }
 
-    pa_stream_drop(pulse->pStream);
-
-unlock_and_exit:
-    pa_threaded_mainloop_unlock(g_pMainLoop);
-
-    return csDecr;
+exit:
+    return read_frames;
 }
 
-static int pulse_read (SWVoiceIn *sw, void *buf, int size)
-{
+static int pulse_read (SWVoiceIn *sw, void *buf, int size) {
     return audio_pcm_sw_read (sw, buf, size);
 }
 
-static int pulse_ctl_in (HWVoiceIn *hw, int cmd, ...)
-{
+static int pulse_ctl_in (HWVoiceIn *hw, int cmd, ...) {
+    PulseVoice *pulse = (PulseVoice *)hw;
+
+    switch (cmd) {
+        case VOICE_ENABLE:
+            pulse_ctrl((PulseVoice *)hw, unpause);
+            break;
+        case VOICE_DISABLE:
+            if (pulse->peek_buffer) {
+                pa_stream_drop(pulse->stream);
+                pulse->peek_buffer = NULL;
+            }
+            pulse_ctrl((PulseVoice *)hw, pause);
+            break;
+        default:
+            return -1;
+    }
     return 0;
 }
 
-static void *pulse_audio_init (void)
-{
+static void *pulse_audio_init (void) {
     int rc;
 
     rc = audioLoadPulseLib();
-    if (RT_FAILURE(rc))
-    {
+    if (RT_FAILURE(rc)) {
         LogRel(("Pulse: Failed to load the PulseAudio shared library! Error %Rrc\n", rc));
         return NULL;
     }
-    if (!(g_pMainLoop = pa_threaded_mainloop_new()))
-    {
+
+    if (!(g_pMainLoop = pa_threaded_mainloop_new())) {
         LogRel(("Pulse: Failed to allocate main loop: %s\n",
                  pa_strerror(pa_context_errno(g_pContext))));
         goto fail;
     }
-    if (!(g_pContext = pa_context_new(pa_threaded_mainloop_get_api(g_pMainLoop), "VBox")))
-    {
+
+    if (!(g_pContext = pa_context_new(pa_threaded_mainloop_get_api(g_pMainLoop), "VBox"))) {
         LogRel(("Pulse: Failed to allocate context: %s\n",
                  pa_strerror(pa_context_errno(g_pContext))));
         goto fail;
     }
-    if (pa_threaded_mainloop_start(g_pMainLoop) < 0)
-    {
+
+    if (pa_threaded_mainloop_start(g_pMainLoop) < 0) {
         LogRel(("Pulse: Failed to start threaded mainloop: %s\n",
                  pa_strerror(pa_context_errno(g_pContext))));
         goto fail;
@@ -649,23 +596,20 @@
     pa_context_set_state_callback(g_pContext, context_state_callback, NULL);
     pa_threaded_mainloop_lock(g_pMainLoop);
 
-    if (pa_context_connect(g_pContext, /*server=*/NULL, 0, NULL) < 0)
-    {
+    if (pa_context_connect(g_pContext, /*server=*/NULL, 0, NULL) < 0) {
         LogRel(("Pulse: Failed to connect to server: %s\n",
                  pa_strerror(pa_context_errno(g_pContext))));
         goto unlock_and_fail;
     }
 
     /* Wait until the g_pContext is ready */
-    for (;;)
-    {
+    for (;;) {
         pa_context_state_t cstate;
         pa_threaded_mainloop_wait(g_pMainLoop);
         cstate = pa_context_get_state(g_pContext);
         if (cstate == PA_CONTEXT_READY)
             break;
-        else if (cstate == PA_CONTEXT_TERMINATED || cstate == PA_CONTEXT_FAILED)
-        {
+        else if (cstate == PA_CONTEXT_TERMINATED || cstate == PA_CONTEXT_FAILED) {
             LogRel(("Pulse: Failed to initialize context (state %d)\n", cstate));
             goto unlock_and_fail;
         }
@@ -682,40 +626,39 @@
     if (g_pMainLoop)
         pa_threaded_mainloop_stop(g_pMainLoop);
 
-    if (g_pContext)
-    {
+    if (g_pContext) {
         pa_context_disconnect(g_pContext);
         pa_context_unref(g_pContext);
         g_pContext = NULL;
     }
-    if (g_pMainLoop)
-    {
+
+    if (g_pMainLoop) {
         pa_threaded_mainloop_free(g_pMainLoop);
         g_pMainLoop = NULL;
     }
+
     return NULL;
 }
 
-static void pulse_audio_fini (void *opaque)
-{
+static void pulse_audio_fini (void *opaque) {
     if (g_pMainLoop)
         pa_threaded_mainloop_stop(g_pMainLoop);
-    if (g_pContext)
-    {
+
+    if (g_pContext) {
         pa_context_disconnect(g_pContext);
         pa_context_unref(g_pContext);
         g_pContext = NULL;
     }
-    if (g_pMainLoop)
-    {
+
+    if (g_pMainLoop) {
         pa_threaded_mainloop_free(g_pMainLoop);
         g_pMainLoop = NULL;
     }
+
     (void) opaque;
 }
 
-static struct audio_option pulse_options[] =
-{
+static struct audio_option pulse_options[] = {
     {"DAC_MS", AUD_OPT_INT, &conf.buffer_msecs_out,
      "DAC period size in milliseconds", NULL, 0},
     {"ADC_MS", AUD_OPT_INT, &conf.buffer_msecs_in,
@@ -723,8 +666,7 @@
     {NULL, 0, NULL, NULL, NULL, 0}
 };
 
-static struct audio_pcm_ops pulse_pcm_ops =
-{
+static struct audio_pcm_ops pulse_pcm_ops = {
     pulse_init_out,
     pulse_fini_out,
     pulse_run_out,
@@ -738,8 +680,7 @@
     pulse_ctl_in
 };
 
-struct audio_driver pulse_audio_driver =
-{
+struct audio_driver pulse_audio_driver = {
     INIT_FIELD (name           = ) "pulse",
     INIT_FIELD (descr          = ) "PulseAudio http://www.pulseaudio.org",
     INIT_FIELD (options        = ) pulse_options,
