Index: trunk/src/VBox/Devices/Audio/DrvAudio.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 62579)
+++ trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 62580)
@@ -2180,5 +2180,5 @@
     PDM_DRVREG_CLASS_AUDIO,
     /* cMaxInstances */
-    2,
+    UINT32_MAX,
     /* cbInstance */
     sizeof(DRVAUDIO),
Index: trunk/src/VBox/Devices/Audio/DrvAudio.h
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvAudio.h	(revision 62579)
+++ trunk/src/VBox/Devices/Audio/DrvAudio.h	(revision 62580)
@@ -48,4 +48,6 @@
 #include <iprt/circbuf.h>
 #include <iprt/critsect.h>
+#include <iprt/file.h>
+#include <iprt/path.h>
 
 #include <VBox/vmm/pdmdev.h>
@@ -138,4 +140,6 @@
 const char *DrvAudioHlpAudFmtToStr(PDMAUDIOFMT enmFmt);
 void DrvAudioHlpClearBuf(PPDMPCMPROPS pPCMInfo, void *pvBuf, size_t cbBuf, uint32_t cSamples);
+uint32_t DrvAudioHlpCalcBitrate(uint8_t cBits, uint32_t uHz, uint8_t cChannels);
+uint32_t DrvAudioHlpCalcBitrate(PPDMAUDIOSTREAMCFG pCfg);
 bool DrvAudioHlpPCMPropsAreEqual(PPDMPCMPROPS pPCMProps1, PPDMPCMPROPS pPCMProps2);
 bool DrvAudioHlpPCMPropsAreEqual(PPDMPCMPROPS pPCMProps, PPDMAUDIOSTREAMCFG pCfg);
@@ -147,4 +151,14 @@
 PDMAUDIOFMT DrvAudioHlpStrToAudFmt(const char *pszFmt);
 
+int DrvAudioHlpSanitizeFileName(char *pszPath, size_t cbPath);
+int DrvAudioHlpGetFileName(char *pszFile, size_t cchFile, const char *pszPath, const char *pszName, PDMAUDIOFILETYPE enmType);
+
+int DrvAudioHlpWAVFileOpen(PPDMAUDIOFILE pFile, const char *pszFile, uint32_t fOpen, PPDMPCMPROPS pProps, PDMAUDIOFILEFLAGS fFlags);
+int DrvAudioHlpWAVFileClose(PPDMAUDIOFILE pFile);
+size_t DrvAudioHlpWAVFileGetDataSize(PPDMAUDIOFILE pFile);
+int DrvAudioHlpWAVFileWrite(PPDMAUDIOFILE pFile, const void *pvBuf, size_t cbBuf, uint32_t fFlags);
+
+#define AUDIO_MAKE_FOURCC(c0, c1, c2, c3) RT_H2LE_U32_C(RT_MAKE_U32_FROM_U8(c0, c1, c2, c3))
+
 #endif /* DRV_AUDIO_H */
 
Index: trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp	(revision 62579)
+++ trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp	(revision 62580)
@@ -42,11 +42,11 @@
  * THE SOFTWARE.
  */
-#define LOG_GROUP LOG_GROUP_DRV_AUDIO
-#include <VBox/log.h>
+#include <iprt/alloc.h>
 #include <iprt/asm-math.h>
 #include <iprt/assert.h>
+#include <iprt/dir.h>
+#include <iprt/file.h>
+#include <iprt/string.h>
 #include <iprt/uuid.h>
-#include <iprt/string.h>
-#include <iprt/alloc.h>
 
 #include <VBox/vmm/pdmdev.h>
@@ -61,4 +61,36 @@
 #include "AudioMixBuffer.h"
 
+#pragma pack(1)
+/**
+ * Structure for building up a .WAV file header.
+ */
+typedef struct AUDIOWAVFILEHDR
+{
+    uint32_t u32RIFF;
+    uint32_t u32Size;
+    uint32_t u32WAVE;
+
+    uint32_t u32Fmt;
+    uint32_t u32Size1;
+    uint16_t u16AudioFormat;
+    uint16_t u16NumChannels;
+    uint32_t u32SampleRate;
+    uint32_t u32ByteRate;
+    uint16_t u16BlockAlign;
+    uint16_t u16BitsPerSample;
+
+    uint32_t u32ID2;
+    uint32_t u32Size2;
+} AUDIOWAVFILEHDR, *PAUDIOWAVFILEHDR;
+#pragma pack()
+
+/**
+ * Structure for keeeping the internal .WAV file data
+ */
+typedef struct AUDIOWAVFILEDATA
+{
+    /** The file header/footer. */
+    AUDIOWAVFILEHDR Hdr;
+} AUDIOWAVFILEDATA, *PAUDIOWAVFILEDATA;
 
 /**
@@ -334,4 +366,5 @@
     bool fEqual =    pProps->uHz         == pCfg->uHz
                   && pProps->cChannels   == pCfg->cChannels
+                  && pProps->cbBitrate   == pCfg->cbBitrate
                   && pProps->fSigned     == fSigned
                   && pProps->cBits       == cBits
@@ -345,6 +378,10 @@
     AssertPtrReturn(pProps2, false);
 
+    if (pProps1 == pProps2)
+        return true;
+
     return    pProps1->uHz         == pProps2->uHz
            && pProps1->cChannels   == pProps2->cChannels
+           && pProps1->cbBitrate   == pProps2->cbBitrate
            && pProps1->fSigned     == pProps2->fSigned
            && pProps1->cBits       == pProps2->cBits
@@ -366,4 +403,5 @@
     pCfg->uHz           = pPCMProps->uHz;
     pCfg->cChannels     = pPCMProps->cChannels;
+    pCfg->cbBitrate     = DrvAudioHlpCalcBitrate(pPCMProps->cBits, pPCMProps->uHz, pPCMProps->cChannels) / 8;
     pCfg->enmFormat     = DrvAudioAudFmtBitsToAudFmt(pPCMProps->cBits, pPCMProps->fSigned);
 
@@ -401,6 +439,7 @@
     }
 
+    fValid |= pCfg->uHz > 0;
     /** @todo Check for defined frequencies supported. */
-    fValid |= pCfg->uHz > 0;
+    fValid |= pCfg->cbBitrate > 0;
 
     return fValid;
@@ -456,8 +495,8 @@
         pProps->cBits       = cBits;
         pProps->fSigned     = fSigned;
+        pProps->cShift      = (pCfg->cChannels == 2) + cShift;
         pProps->cChannels   = pCfg->cChannels;
-        pProps->cShift      = (pCfg->cChannels == 2) + cShift;
         pProps->uAlign      = (1 << pProps->cShift) - 1;
-        pProps->cbBitrate   = (pProps->cBits * pProps->uHz * pProps->cChannels) / 8;
+        pProps->cbBitrate   = DrvAudioHlpCalcBitrate(pCfg) / 8;
         pProps->fSwapEndian = pCfg->enmEndianness != PDMAUDIOHOSTENDIANNESS;
     }
@@ -497,4 +536,6 @@
     }
 
+    LogFlow((", bitrate=%RU32", pCfg->cbBitrate));
+
     LogFlow((", endianness="));
     switch (pCfg->enmEndianness)
@@ -512,2 +553,252 @@
 }
 
+uint32_t DrvAudioHlpCalcBitrate(uint8_t cBits, uint32_t uHz, uint8_t cChannels)
+{
+    return (cBits * uHz * cChannels);
+}
+
+uint32_t DrvAudioHlpCalcBitrate(PPDMAUDIOSTREAMCFG pCfg)
+{
+    return DrvAudioHlpCalcBitrate(DrvAudioHlpAudFmtToBits(pCfg->enmFormat), pCfg->uHz, pCfg->cChannels);
+}
+
+/**
+ * Sanitizes the file name component so that unsupported characters
+ * will be replaced by an underscore ("_").
+ *
+ * @return  IPRT status code.
+ * @param   pszPath             Path to sanitize.
+ * @param   cbPath              Size (in bytes) of path to sanitize.
+ */
+int DrvAudioHlpSanitizeFileName(char *pszPath, size_t cbPath)
+{
+    int rc = VINF_SUCCESS;
+#ifdef RT_OS_WINDOWS
+    /* Filter out characters not allowed on Windows platforms, put in by
+       RTTimeSpecToString(). */
+    /** @todo Use something like RTPathSanitize() when available. Later. */
+    RTUNICP aCpSet[] =
+        { ' ', ' ', '(', ')', '-', '.', '0', '9', 'A', 'Z', 'a', 'z', '_', '_',
+          0xa0, 0xd7af, '\0' };
+    ssize_t cReplaced = RTStrPurgeComplementSet(pszPath, aCpSet, '_' /* Replacement */);
+    if (cReplaced < 0)
+        rc = VERR_INVALID_UTF8_ENCODING;
+#endif
+    return rc;
+}
+
+/**
+ * Constructs an unique file name, based on the given path and the audio file type.
+ *
+ * @returns IPRT status code.
+ * @param   pszFile             Where to store the constructed file name.
+ * @param   cchFile             Size (in characters) of the file name buffer.
+ * @param   pszPath             Base path to use.
+ * @param   pszName             A name for better identifying the file. Optional.
+ * @param   enmType             Audio file type to construct file name for.
+ */
+int DrvAudioHlpGetFileName(char *pszFile, size_t cchFile, const char *pszPath, const char *pszName, PDMAUDIOFILETYPE enmType)
+{
+    AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
+    AssertReturn(cchFile,    VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+    /* pszName is optional. */
+
+    int rc;
+
+    do
+    {
+        char szFilePath[RTPATH_MAX];
+        size_t cchFilePath = RTStrPrintf(szFilePath, sizeof(szFilePath), "%s", pszPath);
+
+        /* Create it when necessary. */
+        if (!RTDirExists(szFilePath))
+        {
+            rc = RTDirCreateFullPath(szFilePath, RTFS_UNIX_IRWXU);
+            if (RT_FAILURE(rc))
+                break;
+        }
+
+        /* The actually drop directory consist of the current time stamp and a
+         * unique number when necessary. */
+        char pszTime[64];
+        RTTIMESPEC time;
+        if (!RTTimeSpecToString(RTTimeNow(&time), pszTime, sizeof(pszTime)))
+        {
+            rc = VERR_BUFFER_OVERFLOW;
+            break;
+        }
+
+        rc = DrvAudioHlpSanitizeFileName(pszTime, sizeof(pszTime));
+        if (RT_FAILURE(rc))
+            break;
+
+        rc = RTPathAppend(szFilePath, sizeof(szFilePath), pszTime);
+        if (RT_FAILURE(rc))
+            break;
+
+        if (pszName) /* Optional name given? */
+        {
+            rc = RTStrCat(szFilePath, sizeof(szFilePath), "-");
+            if (RT_FAILURE(rc))
+                break;
+
+            rc = RTStrCat(szFilePath, sizeof(szFilePath), pszName);
+            if (RT_FAILURE(rc))
+                break;
+        }
+
+        switch (enmType)
+        {
+            case PDMAUDIOFILETYPE_WAV:
+                rc = RTStrCat(szFilePath, sizeof(szFilePath), ".wav");
+                break;
+
+            default:
+                AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
+        }
+
+        if (RT_FAILURE(rc))
+            break;
+
+        RTStrPrintf(pszFile, cchFile, "%s", szFilePath);
+
+    } while (0);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+int DrvAudioHlpWAVFileOpen(PPDMAUDIOFILE pFile, const char *pszFile, uint32_t fOpen, PPDMPCMPROPS pProps,
+                           PDMAUDIOFILEFLAGS fFlags)
+{
+    AssertPtrReturn(pFile,   VERR_INVALID_POINTER);
+    AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
+    /** @todo Validate fOpen flags. */
+    AssertPtrReturn(pProps,  VERR_INVALID_POINTER);
+    /** @todo Validate fFlags flags. */
+
+    Assert(pProps->cChannels);
+    Assert(pProps->uHz);
+    Assert(pProps->cbBitrate);
+    Assert(pProps->cBits);
+
+    pFile->pvData = (PAUDIOWAVFILEDATA)RTMemAllocZ(sizeof(AUDIOWAVFILEDATA));
+    if (!pFile->pvData)
+        return VERR_NO_MEMORY;
+    pFile->cbData = sizeof(PAUDIOWAVFILEDATA);
+
+    PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
+    AssertPtr(pData);
+
+    /* Header. */
+    pData->Hdr.u32RIFF          = AUDIO_MAKE_FOURCC('R','I','F','F');
+    pData->Hdr.u32Size          = 36;
+    pData->Hdr.u32WAVE          = AUDIO_MAKE_FOURCC('W','A','V','E');
+
+    pData->Hdr.u32Fmt           = AUDIO_MAKE_FOURCC('f','m','t',' ');
+    pData->Hdr.u32Size1         = 16; /* Means PCM. */
+    pData->Hdr.u16AudioFormat   = 1;  /* PCM, linear quantization. */
+    pData->Hdr.u16NumChannels   = pProps->cChannels;
+    pData->Hdr.u32SampleRate    = pProps->uHz;
+    pData->Hdr.u32ByteRate      = pProps->cbBitrate / 8;
+    pData->Hdr.u16BlockAlign    = pProps->cChannels * pProps->cBits / 8;
+    pData->Hdr.u16BitsPerSample = pProps->cBits;
+
+    /* Data chunk. */
+    pData->Hdr.u32ID2           = AUDIO_MAKE_FOURCC('d','a','t','a');
+    pData->Hdr.u32Size2         = 0;
+
+    int rc = RTFileOpen(&pFile->hFile, pszFile, fOpen);
+    if (RT_SUCCESS(rc))
+    {
+        rc = RTFileWrite(pFile->hFile, &pData->Hdr, sizeof(pData->Hdr), NULL);
+        if (RT_FAILURE(rc))
+        {
+            RTFileClose(pFile->hFile);
+            pFile->hFile = NIL_RTFILE;
+        }
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        pFile->enmType = PDMAUDIOFILETYPE_WAV;
+
+        RTStrPrintf(pFile->szName, RT_ELEMENTS(pFile->szName), "%s", pszFile);
+    }
+    else
+    {
+        RTMemFree(pFile->pvData);
+        pFile->pvData = NULL;
+        pFile->cbData = 0;
+    }
+
+    return rc;
+}
+
+int DrvAudioHlpWAVFileClose(PPDMAUDIOFILE pFile)
+{
+    AssertPtrReturn(pFile, VERR_INVALID_POINTER);
+
+    Assert(pFile->enmType == PDMAUDIOFILETYPE_WAV);
+
+    if (pFile->hFile != NIL_RTFILE)
+    {
+        PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
+        AssertPtr(pData);
+
+        /* Update the header with the current data size. */
+        RTFileWriteAt(pFile->hFile, 0, &pData->Hdr, sizeof(pData->Hdr), NULL);
+
+        RTFileClose(pFile->hFile);
+        pFile->hFile = NIL_RTFILE;
+    }
+
+    if (pFile->pvData)
+    {
+        RTMemFree(pFile->pvData);
+        pFile->pvData = NULL;
+    }
+
+    pFile->cbData  = 0;
+    pFile->enmType = PDMAUDIOFILETYPE_UNKNOWN;
+
+    return VINF_SUCCESS;
+}
+
+size_t DrvAudioHlpWAVFileGetDataSize(PPDMAUDIOFILE pFile)
+{
+    AssertPtrReturn(pFile, VERR_INVALID_POINTER);
+
+    Assert(pFile->enmType == PDMAUDIOFILETYPE_WAV);
+
+    PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
+    AssertPtr(pData);
+
+    return pData->Hdr.u32Size2;
+}
+
+int DrvAudioHlpWAVFileWrite(PPDMAUDIOFILE pFile, const void *pvBuf, size_t cbBuf, uint32_t fFlags)
+{
+    AssertPtrReturn(pFile, VERR_INVALID_POINTER);
+    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+    /** @todo Validate fFlags. */
+
+    Assert(pFile->enmType == PDMAUDIOFILETYPE_WAV);
+
+    if (!cbBuf)
+        return VINF_SUCCESS;
+
+    PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
+    AssertPtr(pData);
+
+    int rc = RTFileWrite(pFile->hFile, pvBuf, cbBuf, NULL);
+    if (RT_SUCCESS(rc))
+    {
+        pData->Hdr.u32Size  += (uint32_t)cbBuf;
+        pData->Hdr.u32Size2 += (uint32_t)cbBuf;
+    }
+
+    return rc;
+}
+
Index: trunk/src/VBox/Devices/Audio/DrvHostDebugAudio.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostDebugAudio.cpp	(revision 62580)
+++ trunk/src/VBox/Devices/Audio/DrvHostDebugAudio.cpp	(revision 62580)
@@ -0,0 +1,429 @@
+/* $Id$ */
+/** @file
+ * Debug audio driver -- host backend for dumping and injecting audio data
+ * from/to the device emulation.
+ */
+
+/*
+ * Copyright (C) 2016 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.
+ * --------------------------------------------------------------------
+ */
+
+#include <iprt/alloc.h>
+#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
+
+#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
+#include <VBox/log.h>
+#include <VBox/vmm/pdmaudioifs.h>
+
+#include "DrvAudio.h"
+#include "AudioMixBuffer.h"
+#include "VBoxDD.h"
+
+
+/**
+ * Structure for keeping a debug input/output stream.
+ */
+typedef struct DEBUGAUDIOSTREAM
+{
+    /** Note: Always must come first! */
+    PDMAUDIOSTREAM     Stream;
+    /** Audio file to dump output to or read input from. */
+    PDMAUDIOFILE       File;
+    union
+    {
+        struct
+        {
+            /** Timestamp of last captured samples. */
+            uint64_t   tsLastCaptured;
+        } In;
+        struct
+        {
+            /** Timestamp of last played samples. */
+            uint64_t   tsLastPlayed;
+            uint64_t   csPlayBuffer;
+            uint8_t   *pu8PlayBuffer;
+        } Out;
+    };
+
+} DEBUGAUDIOSTREAM, *PDEBUGAUDIOSTREAM;
+
+/**
+ * Debug audio driver instance data.
+ * @implements PDMIAUDIOCONNECTOR
+ */
+typedef struct DRVHOSTDEBUGAUDIO
+{
+    /** Pointer to the driver instance structure. */
+    PPDMDRVINS    pDrvIns;
+    /** Pointer to host audio interface. */
+    PDMIHOSTAUDIO IHostAudio;
+} DRVHOSTDEBUGAUDIO, *PDRVHOSTDEBUGAUDIO;
+
+/*******************************************PDM_AUDIO_DRIVER******************************/
+
+
+static DECLCALLBACK(int) drvHostDebugAudioGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+
+    pCfg->cbStreamOut    = sizeof(DEBUGAUDIOSTREAM);
+    pCfg->cbStreamIn     = sizeof(DEBUGAUDIOSTREAM);
+
+    /* The NULL backend has exactly one input source and one output sink. */
+    pCfg->cSources       = 1;
+    pCfg->cSinks         = 1;
+
+    pCfg->cMaxStreamsOut = 1; /* Output */
+    pCfg->cMaxStreamsIn  = 2; /* Line input + microphone input. */
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostDebugAudioInit(PPDMIHOSTAUDIO pInterface)
+{
+    NOREF(pInterface);
+
+    LogFlowFuncLeaveRC(VINF_SUCCESS);
+    return VINF_SUCCESS;
+}
+
+static int debugCreateStreamIn(PPDMIHOSTAUDIO pInterface,
+                               PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfg, uint32_t *pcSamples)
+{
+    NOREF(pInterface);
+
+    /* Just adopt the wanted stream configuration. */
+    int rc = DrvAudioHlpStreamCfgToProps(pCfg, &pStream->Props);
+    if (RT_SUCCESS(rc))
+    {
+        if (pcSamples)
+            *pcSamples = _1K;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static int debugCreateStreamOut(PPDMIHOSTAUDIO pInterface,
+                                PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfg,
+                                uint32_t *pcSamples)
+{
+    NOREF(pInterface);
+
+    PDEBUGAUDIOSTREAM pDbgStream = (PDEBUGAUDIOSTREAM)pStream;
+
+    /* Just adopt the wanted stream configuration. */
+    PDMPCMPROPS Props;
+    int rc = DrvAudioHlpStreamCfgToProps(pCfg, &Props);
+    if (RT_SUCCESS(rc))
+    {
+        pDbgStream->Out.tsLastPlayed  = 0;
+        pDbgStream->Out.csPlayBuffer  = _1K;
+        pDbgStream->Out.pu8PlayBuffer = (uint8_t *)RTMemAlloc(pDbgStream->Out.csPlayBuffer << Props.cShift);
+        if (!pDbgStream->Out.pu8PlayBuffer)
+            rc = VERR_NO_MEMORY;
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        char szFile[RTPATH_MAX];
+        rc = DrvAudioHlpGetFileName(szFile, RT_ELEMENTS(szFile), "/tmp/", NULL, PDMAUDIOFILETYPE_WAV);
+        if (RT_SUCCESS(rc))
+        {
+            LogRel(("DebugAudio: Creating output file '%s'\n", szFile));
+            rc = DrvAudioHlpWAVFileOpen(&pDbgStream->File, szFile,
+                                        RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE,
+                                        &Props, PDMAUDIOFILEFLAG_NONE);
+            if (RT_FAILURE(rc))
+                LogRel(("DebugAudio: Creating output file '%s' failed with %Rrc\n", szFile, rc));
+        }
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        if (pcSamples)
+            *pcSamples = pDbgStream->Out.csPlayBuffer;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostDebugAudioStreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream,
+                                                     uint32_t *pcSamplesPlayed)
+{
+    PDRVHOSTDEBUGAUDIO pDrv       = RT_FROM_MEMBER(pInterface, DRVHOSTDEBUGAUDIO, IHostAudio);
+    PDEBUGAUDIOSTREAM  pDbgStream = (PDEBUGAUDIOSTREAM)pStream;
+
+    /* Consume as many samples as would be played at the current frequency since last call. */
+    uint32_t cLive           = AudioMixBufLive(&pStream->MixBuf);
+
+    uint64_t u64TicksNow     = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
+    uint64_t u64TicksElapsed = u64TicksNow  - pDbgStream->Out.tsLastPlayed;
+    uint64_t u64TicksFreq    = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
+
+    /*
+     * Minimize the rounding error by adding 0.5: samples = int((u64TicksElapsed * samplesFreq) / u64TicksFreq + 0.5).
+     * If rounding is not taken into account then the playback rate will be consistently lower that expected.
+     */
+   // uint64_t cSamplesPlayed = (2 * u64TicksElapsed * pStream->Props.uHz + u64TicksFreq) / u64TicksFreq / 2;
+
+    /* Don't play more than available. */
+    /*if (cSamplesPlayed > cLive)
+        cSamplesPlayed = cLive;*/
+
+    uint32_t cSamplesPlayed = 0;
+    uint32_t cSamplesAvail  = RT_MIN(AudioMixBufUsed(&pStream->MixBuf), pDbgStream->Out.csPlayBuffer);
+    while (cSamplesAvail)
+    {
+        uint32_t cSamplesRead = 0;
+        int rc2 = AudioMixBufReadCirc(&pStream->MixBuf, pDbgStream->Out.pu8PlayBuffer,
+                                      AUDIOMIXBUF_S2B(&pStream->MixBuf, cSamplesAvail), &cSamplesRead);
+
+        if (RT_FAILURE(rc2))
+            LogRel(("DebugAudio: Reading output failed with %Rrc\n", rc2));
+
+        if (!cSamplesRead)
+            break;
+#if 0
+        RTFILE fh;
+        RTFileOpen(&fh, "/tmp/AudioDebug-Output.pcm",
+                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+        RTFileWrite(fh, pDbgStream->Out.pu8PlayBuffer, AUDIOMIXBUF_S2B(&pStream->MixBuf, cSamplesRead), NULL);
+        RTFileClose(fh);
+#endif
+        rc2 = DrvAudioHlpWAVFileWrite(&pDbgStream->File,
+                                      pDbgStream->Out.pu8PlayBuffer, AUDIOMIXBUF_S2B(&pStream->MixBuf, cSamplesRead),
+                                      0 /* fFlags */);
+        if (RT_FAILURE(rc2))
+            LogRel(("DebugAudio: Writing output failed with %Rrc\n", rc2));
+
+        AudioMixBufFinish(&pStream->MixBuf, cSamplesRead);
+
+        Assert(cSamplesAvail >= cSamplesRead);
+        cSamplesAvail -= cSamplesRead;
+
+        cSamplesPlayed += cSamplesRead;
+    };
+
+    /* Remember when samples were consumed. */
+    pDbgStream->Out.tsLastPlayed = u64TicksNow;
+
+    if (pcSamplesPlayed)
+        *pcSamplesPlayed = cSamplesPlayed;
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostDebugAudioStreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream,
+                                                        uint32_t *pcSamplesCaptured)
+{
+    /* Never capture anything. */
+    if (pcSamplesCaptured)
+        *pcSamplesCaptured = 0;
+
+    return VINF_SUCCESS;
+}
+
+static int debugDestroyStreamIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+{
+    LogFlowFuncLeaveRC(VINF_SUCCESS);
+    return VINF_SUCCESS;
+}
+
+static int debugDestroyStreamOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+{
+    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+
+    PDEBUGAUDIOSTREAM pDbgStream = (PDEBUGAUDIOSTREAM)pStream;
+    if (   pDbgStream
+        && pDbgStream->Out.pu8PlayBuffer)
+    {
+        RTMemFree(pDbgStream->Out.pu8PlayBuffer);
+        pDbgStream->Out.pu8PlayBuffer = NULL;
+    }
+
+    size_t cbDataSize = DrvAudioHlpWAVFileGetDataSize(&pDbgStream->File);
+
+    int rc = DrvAudioHlpWAVFileClose(&pDbgStream->File);
+    if (RT_SUCCESS(rc))
+    {
+        /* Delete the file again if nothing but the header was written to it. */
+        if (!cbDataSize)
+            rc = RTFileDelete(pDbgStream->File.szName); /** @todo Make deletion configurable? */
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostDebugAudioGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
+{
+    AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
+
+    return PDMAUDIOBACKENDSTS_RUNNING;
+}
+
+static DECLCALLBACK(int) drvHostDebugAudioStreamCreate(PPDMIHOSTAUDIO pInterface,
+                                                       PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfg, uint32_t *pcSamples)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg,       VERR_INVALID_POINTER);
+
+    int rc;
+    if (pCfg->enmDir == PDMAUDIODIR_IN)
+        rc = debugCreateStreamIn(pInterface,  pStream, pCfg, pcSamples);
+    else
+        rc = debugCreateStreamOut(pInterface, pStream, pCfg, pcSamples);
+
+    LogFlowFunc(("%s: rc=%Rrc\n", pStream->szName, rc));
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostDebugAudioStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
+
+    int rc;
+    if (pStream->enmDir == PDMAUDIODIR_IN)
+        rc = debugDestroyStreamIn(pInterface,  pStream);
+    else
+        rc = debugDestroyStreamOut(pInterface, pStream);
+
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostDebugAudioStreamControl(PPDMIHOSTAUDIO pInterface,
+                                                        PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
+
+    Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(PDMAUDIOSTRMSTS) drvHostDebugAudioStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+{
+    NOREF(pInterface);
+    NOREF(pStream);
+
+    return (  PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED
+            | PDMAUDIOSTRMSTS_FLAG_DATA_READABLE | PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE);
+}
+
+static DECLCALLBACK(int) drvHostDebugAudioStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+{
+    NOREF(pInterface);
+    NOREF(pStream);
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) drvHostDebugAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+    PPDMDRVINS         pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+    PDRVHOSTDEBUGAUDIO pThis   = PDMINS_2_DATA(pDrvIns, PDRVHOSTDEBUGAUDIO);
+
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
+    return NULL;
+}
+
+static DECLCALLBACK(void) drvHostDebugAudioShutdown(PPDMIHOSTAUDIO pInterface)
+{
+    NOREF(pInterface);
+}
+
+/**
+ * Constructs a Null audio driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(int) drvHostDebugAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
+{
+    AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
+    /* pCfg is optional. */
+
+    PDRVHOSTDEBUGAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDEBUGAUDIO);
+    LogRel(("Audio: Initializing DEBUG driver\n"));
+
+    /*
+     * Init the static parts.
+     */
+    pThis->pDrvIns                   = pDrvIns;
+    /* IBase */
+    pDrvIns->IBase.pfnQueryInterface = drvHostDebugAudioQueryInterface;
+    /* IHostAudio */
+    PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostDebugAudio);
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Char driver registration record.
+ */
+const PDMDRVREG g_DrvHostDebugAudio =
+{
+    /* u32Version */
+    PDM_DRVREG_VERSION,
+    /* szName */
+    "DebugAudio",
+    /* szRCMod */
+    "",
+    /* szR0Mod */
+    "",
+    /* pszDescription */
+    "Debug audio host driver",
+    /* fFlags */
+    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+    /* fClass. */
+    PDM_DRVREG_CLASS_AUDIO,
+    /* cMaxInstances */
+    ~0U,
+    /* cbInstance */
+    sizeof(DRVHOSTDEBUGAUDIO),
+    /* pfnConstruct */
+    drvHostDebugAudioConstruct,
+    /* pfnDestruct */
+    NULL,
+    /* pfnRelocate */
+    NULL,
+    /* pfnIOCtl */
+    NULL,
+    /* pfnPowerOn */
+    NULL,
+    /* pfnReset */
+    NULL,
+    /* pfnSuspend */
+    NULL,
+    /* pfnResume */
+    NULL,
+    /* pfnAttach */
+    NULL,
+    /* pfnDetach */
+    NULL,
+    /* pfnPowerOff */
+    NULL,
+    /* pfnSoftReset */
+    NULL,
+    /* u32EndVersion */
+    PDM_DRVREG_VERSION
+};
+
Index: trunk/src/VBox/Devices/Makefile.kmk
===================================================================
--- trunk/src/VBox/Devices/Makefile.kmk	(revision 62579)
+++ trunk/src/VBox/Devices/Makefile.kmk	(revision 62580)
@@ -548,4 +548,10 @@
 	Audio/DrvHostNullAudio.cpp
 
+ ifdef VBOX_WITH_AUDIO_DEBUG
+  VBoxDD_DEFS    += VBOX_WITH_AUDIO_DEBUG
+  VBoxDD_SOURCES += \
+	Audio/DrvHostDebugAudio.cpp
+ endif
+
  ifeq ($(KBUILD_TARGET),darwin)
   VBoxDD_SOURCES += \
Index: trunk/src/VBox/Devices/build/VBoxDD.cpp
===================================================================
--- trunk/src/VBox/Devices/build/VBoxDD.cpp	(revision 62579)
+++ trunk/src/VBox/Devices/build/VBoxDD.cpp	(revision 62580)
@@ -275,4 +275,9 @@
     if (RT_FAILURE(rc))
         return rc;
+#ifdef VBOX_WITH_AUDIO_DEBUG
+    rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvHostDebugAudio);
+    if (RT_FAILURE(rc))
+        return rc;
+#endif
     rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvHostNullAudio);
     if (RT_FAILURE(rc))
Index: trunk/src/VBox/Devices/build/VBoxDD.h
===================================================================
--- trunk/src/VBox/Devices/build/VBoxDD.h	(revision 62579)
+++ trunk/src/VBox/Devices/build/VBoxDD.h	(revision 62580)
@@ -118,4 +118,7 @@
 extern const PDMDRVREG g_DrvNetSniffer;
 extern const PDMDRVREG g_DrvAUDIO;
+#ifdef VBOX_WITH_AUDIO_DEBUG
+extern const PDMDRVREG g_DrvHostDebugAudio;
+#endif
 extern const PDMDRVREG g_DrvHostNullAudio;
 #if defined(RT_OS_WINDOWS)
Index: trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- trunk/src/VBox/Main/Makefile.kmk	(revision 62579)
+++ trunk/src/VBox/Main/Makefile.kmk	(revision 62580)
@@ -274,4 +274,5 @@
 	$(if $(VBOX_WITH_ALSA),VBOX_WITH_ALSA,) \
 	$(if $(VBOX_WITH_PULSE),VBOX_WITH_PULSE,) \
+	$(if $(VBOX_WITH_AUDIO_DEBUG),VBOX_WITH_AUDIO_DEBUG,) \
 	$(if $(VBOX_WITH_VRDE_AUDIO),VBOX_WITH_VRDE_AUDIO,) \
 	$(if $(VBOX_WITH_E1000),VBOX_WITH_E1000,) \
Index: trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp	(revision 62579)
+++ trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp	(revision 62580)
@@ -2923,4 +2923,16 @@
             InsertConfigInteger(pCfg, "Object", (uintptr_t)mAudioVRDE);
             InsertConfigInteger(pCfg, "ObjectVRDPServer", (uintptr_t)mConsoleVRDPServer);
+#endif
+
+#ifdef VBOX_WITH_AUDIO_DEBUG
+            InsertConfigNode(pInst, "LUN#2", &pLunL1);
+            InsertConfigString(pLunL1, "Driver", "AUDIO");
+
+            InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
+            InsertConfigString(pLunL1, "Driver", "DebugAudio");
+
+            InsertConfigNode(pLunL1, "Config", &pCfg);
+            InsertConfigString(pCfg, "AudioDriver", "DebugAudio");
+            InsertConfigString(pCfg, "StreamName", bstr);
 #endif
             /** @todo Add audio video recording driver here. */
