Index: /trunk/src/VBox/Devices/Audio/dsound_template.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/dsound_template.h	(revision 53391)
+++ /trunk/src/VBox/Devices/Audio/dsound_template.h	(revision 53392)
@@ -1,3 +1,18 @@
+/* $Id$ */
+
 /*
+ * Copyright (C) 2014 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on: audio.h
+ *
  * QEMU DirectSound audio driver header
  *
@@ -146,14 +161,16 @@
 #ifdef DSBTYPE_IN
 static void dsound_fini_in (HWVoiceIn *hw)
+{
+    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
+    dsoundCaptureClose (ds);
+    ds->last_read_pos = 0;
+    ds->capture_buffer_size = 0;
+    memset (&ds->as, 0, sizeof(ds->as));
+}
 #else
 static void dsound_fini_out (HWVoiceOut *hw)
-#endif
 {
     HRESULT hr;
-#ifdef DSBTYPE_IN
-    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
-#else
     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
-#endif
 
     if (ds->FIELD) {
@@ -170,10 +187,27 @@
     }
 }
+#endif
 
 #ifdef DSBTYPE_IN
 static int dsound_init_in (HWVoiceIn *hw, audsettings_t *as)
+{
+    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
+
+    ds->last_read_pos = 0;
+    ds->capture_buffer_size = 0;
+    ds->dsound_capture_buffer = NULL;
+    ds->as = *as;
+
+    /* Init default settings. */
+    audio_pcm_init_info (&hw->info, &ds->as);
+    hw->samples = conf.bufsize_in >> hw->info.shift;
+
+    /* Try to open capture in case the device is already there. */
+    dsoundCaptureOpen (ds);
+
+    return 0;
+}
 #else
 static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as)
-#endif
 {
     int err;
@@ -182,15 +216,8 @@
     WAVEFORMATEX wfx;
     audsettings_t obt_as;
-#ifdef DSBTYPE_IN
-    const char *typ = "ADC";
-    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
-    DSCBUFFERDESC bd;
-    DSCBCAPS bc;
-#else
     const char *typ = "DAC";
     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
     DSBUFFERDESC bd;
     DSBCAPS bc;
-#endif
 
     err = waveformat_from_audio_settings (&wfx, as);
@@ -199,21 +226,7 @@
     }
 
-#ifdef DSBTYPE_IN
-    if (!s->dsound_capture)
-        return -1;
-#endif
-
     memset (&bd, 0, sizeof (bd));
     bd.dwSize = sizeof (bd);
     bd.lpwfxFormat = &wfx;
-#ifdef DSBTYPE_IN
-    bd.dwBufferBytes = conf.bufsize_in;
-    hr = IDirectSoundCapture_CreateCaptureBuffer (
-        s->dsound_capture,
-        &bd,
-        &ds->dsound_capture_buffer,
-        NULL
-        );
-#else
     bd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
     bd.dwBufferBytes = conf.bufsize_out;
@@ -224,5 +237,4 @@
         NULL
         );
-#endif
 
     if (FAILED (hr)) {
@@ -285,4 +297,5 @@
     return -1;
 }
+#endif
 
 #undef NAME
Index: /trunk/src/VBox/Devices/Audio/dsoundaudio.c
===================================================================
--- /trunk/src/VBox/Devices/Audio/dsoundaudio.c	(revision 53391)
+++ /trunk/src/VBox/Devices/Audio/dsoundaudio.c	(revision 53392)
@@ -1,3 +1,21 @@
+/* $Id$ */
+/** @file
+ * DirectSound Windows Host Audio Backend.
+ */
+
 /*
+ * Copyright (C) 2014 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on: dsoundaudio.c
+ *
  * QEMU DirectSound audio driver
  *
@@ -45,4 +63,17 @@
 
 /* #define DEBUG_DSOUND */
+
+#define DSLOGF(a) do { LogRel2(a); } while(0)
+#define DSLOGREL(a)                 \
+    do {                            \
+        static int8_t scLogged = 0; \
+        if (scLogged < 8) {         \
+            ++scLogged;             \
+            LogRel(a);              \
+        }                           \
+        else {                      \
+            DSLOGF(a);              \
+        }                           \
+    } while (0)
 
 static struct {
@@ -79,4 +110,6 @@
     LPDIRECTSOUNDBUFFER dsound_primary_buffer;
     audsettings_t settings;
+    LPCGUID devguidp;
+    LPCGUID devguidp_capture;
 } dsound;
 
@@ -97,6 +130,9 @@
 typedef struct {
     HWVoiceIn hw;
-    int first_time;
+    int last_read_pos;
+    int capture_buffer_size;
     LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer;
+    audsettings_t as;
+    HRESULT hr_last_run_in;
 } DSoundVoiceIn;
 
@@ -408,4 +444,214 @@
 
     return 0;
+}
+
+static void dsoundCaptureInterfaceRelease (dsound *s)
+{
+    if (s->dsound_capture) {
+        HRESULT hr = IDirectSoundCapture_Release (s->dsound_capture);
+        if (FAILED (hr)) {
+            DSLOGF(("DSound: DirectSoundCapture release %Rhrc\n", hr));
+        }
+        s->dsound_capture = NULL;
+    }
+}
+
+static int dsoundCaptureInterfaceCreate (dsound *s)
+{
+    HRESULT hr;
+
+    if (s->dsound_capture != NULL) {
+        DSLOGF(("DSound: DirectSoundCapture instance already exists\n"));
+        return -1;
+    }
+
+    hr = CoCreateInstance (&CLSID_DirectSoundCapture, NULL, CLSCTX_ALL,
+                           &IID_IDirectSoundCapture, (void **) &s->dsound_capture);
+    if (FAILED (hr)) {
+        DSLOGREL(("DSound: DirectSoundCapture create instance %Rhrc\n", hr));
+    }
+    else {
+        hr = IDirectSoundCapture_Initialize (s->dsound_capture, s->devguidp_capture);
+        if (FAILED (hr)) {
+            DSLOGREL(("DSound: DirectSoundCapture initialize %Rhrc\n", hr));
+            dsoundCaptureInterfaceRelease (s);
+        }
+    }
+
+    return SUCCEEDED (hr)? 0: -1;
+}
+
+static void dsoundCaptureClose (DSoundVoiceIn *ds)
+{
+    dsound *s = &glob_dsound;
+
+    DSLOGF(("DSound: capture close %p buffer %p\n", ds, ds->dsound_capture_buffer));
+
+    if (ds->dsound_capture_buffer) {
+        HRESULT hr = IDirectSoundCaptureBuffer_Stop (ds->dsound_capture_buffer);
+        if (FAILED (hr)) {
+            DSLOGF(("DSound: close capture buffer stop %Rhrc\n", hr));
+        }
+
+        hr = IDirectSoundCaptureBuffer_Release (ds->dsound_capture_buffer);
+        if (FAILED (hr)) {
+            DSLOGF(("DSound: close capture buffer release %Rhrc\n", hr));
+        }
+        ds->dsound_capture_buffer = NULL;
+    }
+
+    dsoundCaptureInterfaceRelease (s);
+}
+
+static int dsoundCaptureOpen (DSoundVoiceIn *ds)
+{
+    dsound *s = &glob_dsound;
+
+    int err;
+    HRESULT hr;
+    WAVEFORMATEX wfx;
+    DSCBUFFERDESC bd;
+    DSCBCAPS bc;
+    DWORD cpos;
+
+    DSLOGF(("DSound: capture open %p size %d samples, freq %d, chan %d, bits %d, sign %d\n",
+            ds,
+            ds->hw.samples,
+            ds->hw.info.freq,
+            ds->hw.info.nchannels,
+            ds->hw.info.bits,
+            ds->hw.info.sign));
+
+    if (ds->dsound_capture_buffer != NULL) {
+        /* Should not happen but be forgiving. */
+        DSLOGREL(("DSound: DirectSoundCaptureBuffer already exists\n"));
+        dsoundCaptureClose (ds);
+    }
+
+    err = waveformat_from_audio_settings (&wfx, &ds->as);
+    if (err) {
+        return err;
+    }
+
+    err = dsoundCaptureInterfaceCreate (s);
+    if (err) {
+        return err;
+    }
+
+    memset (&bd, 0, sizeof (bd));
+    bd.dwSize = sizeof (bd);
+    bd.lpwfxFormat = &wfx;
+    bd.dwBufferBytes = ds->hw.samples << ds->hw.info.shift;
+    hr = IDirectSoundCapture_CreateCaptureBuffer (s->dsound_capture,
+                                                  &bd, &ds->dsound_capture_buffer, NULL);
+
+    if (FAILED (hr)) {
+        DSLOGREL(("DSound: create capture buffer %Rhrc\n", hr));
+        ds->dsound_capture_buffer = NULL;
+        goto fail0;
+    }
+
+    /* Query the actual parameters. */
+
+    hr = IDirectSoundCaptureBuffer_GetCurrentPosition (ds->dsound_capture_buffer, &cpos, NULL);
+    if (FAILED (hr)) {
+        cpos = 0;
+        DSLOGF(("DSound: open GetCurrentPosition %Rhrc\n", hr));
+    }
+
+    memset (&wfx, 0, sizeof (wfx));
+    hr = IDirectSoundCaptureBuffer_GetFormat (ds->dsound_capture_buffer, &wfx, sizeof (wfx), NULL);
+    if (FAILED (hr)) {
+        DSLOGREL(("DSound: capture buffer GetFormat %Rhrc\n", hr));
+        goto fail0;
+    }
+
+    memset (&bc, 0, sizeof (bc));
+    bc.dwSize = sizeof (bc);
+    hr = IDirectSoundCaptureBuffer_GetCaps (ds->dsound_capture_buffer, &bc);
+    if (FAILED (hr)) {
+        DSLOGREL(("DSound: capture buffer GetCaps %Rhrc\n", hr));
+        goto fail0;
+    }
+
+    DSLOGF(("DSound: capture buffer format: size %d bytes\n"
+            "  tag             = %d\n"
+            "  nChannels       = %d\n"
+            "  nSamplesPerSec  = %d\n"
+            "  nAvgBytesPerSec = %d\n"
+            "  nBlockAlign     = %d\n"
+            "  wBitsPerSample  = %d\n"
+            "  cbSize          = %d\n",
+            bc.dwBufferBytes,
+            wfx.wFormatTag,
+            wfx.nChannels,
+            wfx.nSamplesPerSec,
+            wfx.nAvgBytesPerSec,
+            wfx.nBlockAlign,
+            wfx.wBitsPerSample,
+            wfx.cbSize));
+
+    if (bc.dwBufferBytes & ds->hw.info.align) {
+        DSLOGREL(("DSound: GetCaps returned misaligned buffer size %ld, alignment %d\n",
+                  bc.dwBufferBytes, ds->hw.info.align + 1));
+    }
+
+    if (ds->hw.samples != 0 && ds->hw.samples != (bc.dwBufferBytes >> ds->hw.info.shift)) {
+        DSLOGREL(("DSound: buffer size mismatch dsound %d, hw %d bytes\n",
+                  bc.dwBufferBytes, ds->hw.samples << ds->hw.info.shift));
+    }
+
+    /* Initial state: reading at the initial capture position. */
+    ds->hw.wpos = 0;
+    ds->last_read_pos = cpos >> ds->hw.info.shift;
+    ds->capture_buffer_size = bc.dwBufferBytes >> ds->hw.info.shift;
+    DSLOGF(("DSound: open last_read_pos %d, capture_buffer_size %d\n", ds->last_read_pos, ds->capture_buffer_size));
+
+    ds->hr_last_run_in = S_OK;
+
+    return 0;
+
+ fail0:
+    dsoundCaptureClose (ds);
+    return -1;
+}
+
+static void dsoundCaptureStop (DSoundVoiceIn *ds)
+{
+    if (ds->dsound_capture_buffer) {
+        HRESULT hr = IDirectSoundCaptureBuffer_Stop (ds->dsound_capture_buffer);
+        if (FAILED (hr)) {
+            DSLOGF(("DSound: stop capture buffer %Rhrc\n", hr));
+        }
+    }
+}
+
+static int dsoundCaptureStart (DSoundVoiceIn *ds)
+{
+    HRESULT hr;
+    DWORD status;
+
+    if (ds->dsound_capture_buffer != NULL) {
+        hr = IDirectSoundCaptureBuffer_GetStatus (ds->dsound_capture_buffer, &status);
+        if (FAILED (hr)) {
+            DSLOGF(("DSound: start GetStatus %Rhrc\n", hr));
+        }
+        else {
+            if (status & DSCBSTATUS_CAPTURING) {
+                DSLOGF(("DSound: already capturing\n"));
+            }
+            else {
+                hr = IDirectSoundCaptureBuffer_Start (ds->dsound_capture_buffer, DSCBSTART_LOOPING);
+                if (FAILED (hr)) {
+                    DSLOGREL(("DSound: start %Rhrc\n", hr));
+                }
+            }
+        }
+    }
+    else {
+        hr = E_FAIL;
+    }
+
+    return SUCCEEDED (hr)? 0: -1;
 }
 
@@ -833,49 +1079,21 @@
 static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...)
 {
-    HRESULT hr;
-    DWORD status;
     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
-    LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
-
-    if (!dscb) {
-        dolog ("Attempt to control capture voice without a buffer\n");
-        return -1;
-    }
 
     switch (cmd) {
     case VOICE_ENABLE:
-        if (dsound_get_status_in (dscb, &status)) {
-            return -1;
-        }
-
-        if (status & DSCBSTATUS_CAPTURING) {
-            dolog ("warning: Voice is already capturing\n");
-            return 0;
-        }
-
-        /* clear ?? */
-
-        hr = IDirectSoundCaptureBuffer_Start (dscb, DSCBSTART_LOOPING);
-        if (FAILED (hr)) {
-            dsound_logerr (hr, "Could not start capturing\n");
-            return -1;
-        }
-        break;
-
-    case VOICE_DISABLE:
-        if (dsound_get_status_in (dscb, &status)) {
-            return -1;
-        }
-
-        if (status & DSCBSTATUS_CAPTURING) {
-            hr = IDirectSoundCaptureBuffer_Stop (dscb);
-            if (FAILED (hr)) {
-                dsound_logerr (hr, "Could not stop capturing\n");
+        /* Try to start capture. If it fails, then reopen and try again. */
+        if (dsoundCaptureStart (ds)) {
+            dsoundCaptureClose (ds);
+            dsoundCaptureOpen (ds);
+
+            if (dsoundCaptureStart (ds)) {
                 return -1;
             }
         }
-        else {
-            dolog ("warning: Voice is not capturing\n");
-        }
+        break;
+
+    case VOICE_DISABLE:
+        dsoundCaptureStop (ds);
         break;
     }
@@ -895,13 +1113,14 @@
     LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
     int live, len, dead;
+    int ltmp;
     DWORD blen1, blen2;
-    DWORD len1, len2;
-    DWORD decr;
-    DWORD cpos, rpos;
+    int len1, len2;
+    int decr;
+    DWORD cpos;
     LPVOID p1, p2;
     int hwshift;
 
     if (!dscb) {
-        dolog ("Attempt to run without capture buffer\n");
+        DSLOGF(("DSound: run_in no capture buffer\n"));
         return 0;
     }
@@ -918,27 +1137,23 @@
         dscb,
         &cpos,
-        ds->first_time ? &rpos : NULL
+        NULL
         );
     if (FAILED (hr)) {
-        dsound_logerr (hr, "Could not get capture buffer position\n");
+        if (hr != ds->hr_last_run_in) {
+            DSLOGREL(("DSound: run_in GetCurrentPosition %Rhrc\n", hr));
+        }
+        ds->hr_last_run_in = hr;
         return 0;
     }
-
-    if (ds->first_time) {
-        ds->first_time = 0;
-        if (rpos & hw->info.align) {
-            ldebug ("warning: Misaligned capture read position %ld(%d)\n",
-                    rpos, hw->info.align);
-        }
-        hw->wpos = rpos >> hwshift;
-    }
+    ds->hr_last_run_in = hr;
 
     if (cpos & hw->info.align) {
-        ldebug ("warning: Misaligned capture position %ld(%d)\n",
-                cpos, hw->info.align);
-    }
+        DSLOGF(("DSound: run_in misaligned capture position %ld(%d)\n", cpos, hw->info.align));
+    }
+
     cpos >>= hwshift;
 
-    len = audio_ring_dist (cpos, hw->wpos, hw->samples);
+    /* Number of samples available in the capture buffer. */
+    len = audio_ring_dist (cpos, ds->last_read_pos, ds->capture_buffer_size);
     if (!len) {
         return 0;
@@ -949,5 +1164,5 @@
         dscb,
         &hw->info,
-        hw->wpos << hwshift,
+        ds->last_read_pos << hwshift,
         len << hwshift,
         &p1,
@@ -965,24 +1180,24 @@
     decr = len1 + len2;
 
-#ifndef VBOX
     if (p1 && len1) {
-        hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
+        ltmp = audio_MIN(len1, hw->samples - hw->wpos);
+        hw->conv (hw->conv_buf + hw->wpos, p1, ltmp, &pcm_in_volume);
+        if (len1 > ltmp) {
+            hw->conv (hw->conv_buf, (void *)((uintptr_t)p1 + (ltmp << hwshift)), len1 - ltmp, &pcm_in_volume);
+        }
+        hw->wpos = (hw->wpos + len1) % hw->samples;
     }
 
     if (p2 && len2) {
-        hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
-    }
-#else
-    if (p1 && len1) {
-        hw->conv (hw->conv_buf + hw->wpos, p1, len1, &pcm_in_volume);
-    }
-
-    if (p2 && len2) {
-        hw->conv (hw->conv_buf, p2, len2, &pcm_in_volume);
-    }
-#endif
+        ltmp = audio_MIN(len2, hw->samples - hw->wpos);
+        hw->conv (hw->conv_buf + hw->wpos, p2, ltmp, &pcm_in_volume);
+        if (len2 > ltmp) {
+            hw->conv (hw->conv_buf, (void *)((uintptr_t)p2 + (ltmp << hwshift)), len2 - ltmp, &pcm_in_volume);
+        }
+        hw->wpos = (hw->wpos + len2) % hw->samples;
+    }
 
     dsound_unlock_in (dscb, p1, p2, blen1, blen2);
-    hw->wpos = (hw->wpos + decr) % hw->samples;
+    ds->last_read_pos = (ds->last_read_pos + decr) % ds->capture_buffer_size;
     return decr;
 }
@@ -1081,45 +1296,12 @@
     }
 
-    hr = CoCreateInstance (
-        &CLSID_DirectSoundCapture,
-        NULL,
-        CLSCTX_ALL,
-        &IID_IDirectSoundCapture,
-        (void **) &s->dsound_capture
-        );
-    if (FAILED (hr)) {
-#ifndef VBOX
-        dsound_logerr (hr, "Could not create DirectSoundCapture instance\n");
-#else
-        LogRel(("DSound: Could not create DirectSoundCapture instance\n"));
-        dsound_log_hresult(hr);
-#endif
-    }
-    else {
-        if (conf.device_guid_in) {
-            hr = RTUuidFromStr(&devguid, conf.device_guid_in);
-            if (FAILED (hr)) {
-                LogRel(("DSound: Could not parse DirectSound input device GUID\n"));
-            }
-            devguidp = (LPCGUID)&devguid;
-        } else {
-            devguidp = NULL;
-        }
-        hr = IDirectSoundCapture_Initialize (s->dsound_capture, devguidp);
-        if (FAILED (hr)) {
-#ifndef VBOX
-            dsound_logerr (hr, "Could not initialize DirectSoundCapture\n");
-#else
-            LogRel(("DSound: Could not initialize DirectSoundCapture\n"));
-            dsound_log_hresult(hr);
-#endif
-
-            hr = IDirectSoundCapture_Release (s->dsound_capture);
-            if (FAILED (hr)) {
-                dsound_logerr (hr,
-                               "Could not release DirectSoundCapture\n");
-            }
-            s->dsound_capture = NULL;
-        }
+    if (conf.device_guid_in) {
+        int rc = RTUuidFromStr(&devguid, conf.device_guid_in);
+        if (RT_FAILURE(rc)) {
+            LogRel(("DSound: Could not parse DirectSound input device GUID\n"));
+        }
+        s->devguidp = (LPCGUID)&devguid;
+    } else {
+        s->devguidp = NULL;
     }
 
