Index: trunk/src/VBox/Devices/Audio/AudioMixer.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/AudioMixer.cpp	(revision 73402)
+++ trunk/src/VBox/Devices/Audio/AudioMixer.cpp	(revision 73403)
@@ -70,4 +70,5 @@
 static int audioMixerSinkRemoveStreamInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
 static void audioMixerSinkReset(PAUDMIXSINK pSink);
+static int audioMixerSinkSetRecSourceInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
 static int audioMixerSinkUpdateInternal(PAUDMIXSINK pSink);
 
@@ -614,4 +615,7 @@
      * Always use the sink's PCM audio format as the host side when creating a stream for it.
      */
+    AssertMsg(DrvAudioHlpPCMPropsAreValid(&pSink->PCMProps),
+              ("%s: Does not (yet) have a format set when it must\n", pSink->pszName));
+
     PDMAUDIOSTREAMCFG CfgHost;
     rc = DrvAudioHlpPCMPropsToStreamCfg(&pSink->PCMProps, &CfgHost);
@@ -858,6 +862,14 @@
 # error "Implement me!"
 #else
-        /* Return how much data we can deliver since the last read. */
-        cbReadable = DrvAudioHlpMsToBytes(RTTimeMilliTS() - pSink->tsLastReadWrittenMs, &pSink->PCMProps);
+        PAUDMIXSTREAM pStreamRecSource = pSink->In.pStreamRecSource;
+        if (!pStreamRecSource)
+        {
+            Log3Func(("[%s] No recording source specified, skipping ...\n", pSink->pszName));
+        }
+        else
+        {
+            AssertPtr(pStreamRecSource->pConn);
+            cbReadable = pStreamRecSource->pConn->pfnStreamGetReadable(pStreamRecSource->pConn, pStreamRecSource->pStream);
+        }
 #endif
     }
@@ -869,4 +881,26 @@
 
     return cbReadable;
+}
+
+/**
+ * Returns the sink's current recording source.
+ *
+ * @return  Mixer stream which currently is set as current recording source, NULL if none is set.
+ * @param   pSink               Audio mixer sink to return current recording source for.
+ */
+PAUDMIXSTREAM AudioMixerSinkGetRecordingSource(PAUDMIXSINK pSink)
+{
+    int rc = RTCritSectEnter(&pSink->CritSect);
+    if (RT_FAILURE(rc))
+        return NULL;
+
+    AssertMsg(pSink->enmDir == AUDMIXSINKDIR_INPUT, ("Specified sink is not an input sink\n"));
+
+    PAUDMIXSTREAM pStream = pSink->In.pStreamRecSource;
+
+    int rc2 = RTCritSectLeave(&pSink->CritSect);
+    AssertRC(rc2);
+
+    return pStream;
 }
 
@@ -1067,102 +1101,71 @@
               ("Can't read from a sink which is not an input sink\n"));
 
+    uint32_t cbRead = 0;
+
+    /* Flag indicating whether this sink is in a 'clean' state,
+     * e.g. there is no more data to read from. */
+    bool fClean = true;
+
+    PAUDMIXSTREAM pStreamRecSource = pSink->In.pStreamRecSource;
+    if (!pStreamRecSource)
+    {
+        Log3Func(("[%s] No recording source specified, skipping ...\n", pSink->pszName));
+    }
+    else if (!(pStreamRecSource->pConn->pfnStreamGetStatus(pStreamRecSource->pConn, pStreamRecSource->pStream) & PDMAUDIOSTREAMSTS_FLAG_ENABLED))
+    {
+        Log3Func(("[%s] Stream '%s' disabled, skipping ...\n", pSink->pszName, pStreamRecSource->pszName));
+    }
+    else
+    {
+        uint32_t cbToRead    = RT_MIN(cbBuf,
+                                      pStreamRecSource->pConn->pfnStreamGetReadable(pStreamRecSource->pConn,
+                                                                                    pStreamRecSource->pStream));
+        while (cbToRead)
+        {
+            uint32_t cbReadStrm;
+            AssertPtr(pStreamRecSource->pConn);
 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
 # error "Implement me!"
 #else
-    uint8_t *pvMixBuf = (uint8_t *)RTMemAlloc(cbBuf);
-    if (!pvMixBuf)
-    {
-        int rc2 = RTCritSectLeave(&pSink->CritSect);
-        AssertRC(rc2);
-
-        return VERR_NO_MEMORY;
-    }
+            rc = pStreamRecSource->pConn->pfnStreamRead(pStreamRecSource->pConn, pStreamRecSource->pStream,
+                                                        (uint8_t *)pvBuf + cbRead, cbToRead, &cbReadStrm);
 #endif
-
-    uint32_t cbRead = 0;
-
-    /* Flag indicating whether this sink is in a 'clean' state,
-     * e.g. there is no more data to read from. */
-    bool fClean = true;
-
-    PAUDMIXSTREAM pMixStream;
-    RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
-    {
-        if (!(pMixStream->pConn->pfnStreamGetStatus(pMixStream->pConn, pMixStream->pStream) & PDMAUDIOSTREAMSTS_FLAG_ENABLED))
-        {
-            Log3Func(("[%s] Stream '%s' disabled, skipping ...\n", pSink->pszName, pMixStream->pszName));
-            continue;
-        }
-
-        uint32_t cbTotalRead = 0;
-        uint32_t cbToRead    = cbBuf;
-
-        int rc2 = VINF_SUCCESS;
-
-        while (cbToRead)
-        {
-            uint32_t cbReadStrm;
-            AssertPtr(pMixStream->pConn);
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
-# error "Implement me!"
-#else
-            rc2 = pMixStream->pConn->pfnStreamRead(pMixStream->pConn, pMixStream->pStream,
-                                                   (uint8_t *)pvMixBuf + cbTotalRead, cbToRead, &cbReadStrm);
-#endif
-            if (RT_FAILURE(rc2))
-                LogFunc(("[%s] Failed reading from stream '%s': %Rrc\n", pSink->pszName, pMixStream->pszName, rc2));
-
-            Log3Func(("[%s] Stream '%s': Read %RU32 bytes\n", pSink->pszName, pMixStream->pszName, cbReadStrm));
-
-            if (   RT_FAILURE(rc2)
+            if (RT_FAILURE(rc))
+                LogFunc(("[%s] Failed reading from stream '%s': %Rrc\n", pSink->pszName, pStreamRecSource->pszName, rc));
+
+            Log3Func(("[%s] Stream '%s': Read %RU32 bytes\n", pSink->pszName, pStreamRecSource->pszName, cbReadStrm));
+
+            if (   RT_FAILURE(rc)
                 || !cbReadStrm)
                 break;
 
-            /** @todo Right now we only handle one stream (the last one added in fact). */
-
             AssertBreakStmt(cbReadStrm <= cbToRead, rc = VERR_BUFFER_OVERFLOW);
-            cbToRead    -= cbReadStrm;
-            cbTotalRead += cbReadStrm;
-        }
-
-        if (RT_FAILURE(rc2))
-            continue;
-
-        cbRead = RT_MAX(cbRead, cbTotalRead);
-
-        uint32_t cbReadable = pMixStream->pConn->pfnStreamGetReadable(pMixStream->pConn, pMixStream->pStream);
+            cbToRead -= cbReadStrm;
+            cbRead   += cbReadStrm;
+            Assert(cbRead <= cbBuf);
+        }
+
+        uint32_t cbReadable = pStreamRecSource->pConn->pfnStreamGetReadable(pStreamRecSource->pConn, pStreamRecSource->pStream);
 
         /* Still some data available? Then sink is not clean (yet). */
         if (cbReadable)
             fClean = false;
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        if (fClean)
-            pSink->fStatus &= ~AUDMIXSINK_STS_DIRTY;
-
-        /* Update our last read time stamp. */
-        pSink->tsLastReadWrittenMs = RTTimeMilliTS();
-
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
-# error "Implement me!"
-#else
-        Assert(cbRead <= cbBuf);
-        if (cbRead)
-            memcpy(pvBuf, pvMixBuf, cbRead);
+
+        if (RT_SUCCESS(rc))
+        {
+            if (fClean)
+                pSink->fStatus &= ~AUDMIXSINK_STS_DIRTY;
+
+            /* Update our last read time stamp. */
+            pSink->tsLastReadWrittenMs = RTTimeMilliTS();
+
+#ifdef VBOX_AUDIO_MIXER_DEBUG
+            int rc2 = DrvAudioHlpFileWrite(pSink->Dbg.pFile, pvBuf, cbRead, 0 /* fFlags */);
+            AssertRC(rc2);
 #endif
-
-#ifdef VBOX_AUDIO_MIXER_DEBUG
-        int rc2 = DrvAudioHlpFileWrite(pSink->Dbg.pFile, pvBuf, cbRead, 0 /* fFlags */);
-        AssertRC(rc2);
-#endif
-        if (pcbRead)
-            *pcbRead = cbRead;
-    }
-
-#ifndef VBOX_AUDIO_MIXER_WITH_MIXBUF
-    RTMemFree(pvMixBuf);
-#endif
+            if (pcbRead)
+                *pcbRead = cbRead;
+        }
+    }
 
 #ifdef LOG_ENABLED
@@ -1208,8 +1211,18 @@
     RTListNodeRemove(&pStream->Node);
 
+    int rc = VINF_SUCCESS;
+
+    if (pSink->enmDir == AUDMIXSINKDIR_INPUT)
+    {
+        /* Make sure to also un-set the recording source if this stream was set
+         * as the recording source before. */
+        if (pStream == pSink->In.pStreamRecSource)
+            rc = audioMixerSinkSetRecSourceInternal(pSink, NULL);
+    }
+
     /* Set sink to NULL so that we know we're not part of any sink anymore. */
     pStream->pSink = NULL;
 
-    return VINF_SUCCESS;
+    return rc;
 }
 
@@ -1435,5 +1448,54 @@
 
 /**
- * Set the volume of an individual sink.
+ * Set the current recording source of an input mixer sink, internal version.
+ *
+ * @return  IPRT status code.
+ * @param   pSink               Input mixer sink to set recording source for.
+ * @param   pStream             Mixer stream to set as current recording source. Must be an input stream.
+ *                              Specify NULL to un-set the current recording source.
+ */
+static int audioMixerSinkSetRecSourceInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
+{
+    AssertMsg(pSink->enmDir == AUDMIXSINKDIR_INPUT, ("Specified sink is not an input sink\n"));
+
+    if (pStream) /* Can be NULL if un-setting. */
+    {
+        AssertPtr(pStream->pStream);
+        AssertMsg(pStream->pStream->enmDir == PDMAUDIODIR_IN, ("Specified stream is not an input stream\n"));
+    }
+
+    pSink->In.pStreamRecSource = pStream;
+
+    LogFunc(("[%s] Recording source is now '%s'\n",
+             pSink->pszName, pSink->In.pStreamRecSource ? pSink->In.pStreamRecSource->pszName : "<None>"));
+    return VINF_SUCCESS;
+}
+
+/**
+ * Set the current recording source of an input mixer sink.
+ *
+ * @return  IPRT status code.
+ * @param   pSink               Input mixer sink to set recording source for.
+ * @param   pStream             Mixer stream to set as current recording source. Must be an input stream.
+ */
+int AudioMixerSinkSetRecordingSource(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
+{
+    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+
+    int rc = RTCritSectEnter(&pSink->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    rc = audioMixerSinkSetRecSourceInternal(pSink, pStream);
+
+    int rc2 = RTCritSectLeave(&pSink->CritSect);
+    AssertRC(rc2);
+
+    return rc;
+}
+
+/**
+ * Sets the volume of an individual sink.
  *
  * @returns IPRT status code.
Index: trunk/src/VBox/Devices/Audio/AudioMixer.h
===================================================================
--- trunk/src/VBox/Devices/Audio/AudioMixer.h	(revision 73402)
+++ trunk/src/VBox/Devices/Audio/AudioMixer.h	(revision 73403)
@@ -144,4 +144,6 @@
     uint32_t       cbReadable;
 #endif
+    /** The current recording source. Can be NULL if not set. */
+    PAUDMIXSTREAM  pStreamRecSource;
 } AUDMIXSINKIN;
 
@@ -244,4 +246,5 @@
 uint32_t AudioMixerSinkGetWritable(PAUDMIXSINK pSink);
 AUDMIXSINKDIR AudioMixerSinkGetDir(PAUDMIXSINK pSink);
+PAUDMIXSTREAM AudioMixerSinkGetRecordingSource(PAUDMIXSINK pSink);
 PAUDMIXSTREAM AudioMixerSinkGetStream(PAUDMIXSINK pSink, uint8_t uIndex);
 AUDMIXSINKSTS AudioMixerSinkGetStatus(PAUDMIXSINK pSink);
@@ -254,4 +257,5 @@
 void AudioMixerSinkGetFormat(PAUDMIXSINK pSink, PPDMAUDIOPCMPROPS pPCMProps);
 int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PPDMAUDIOPCMPROPS pPCMProps);
+int AudioMixerSinkSetRecordingSource(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
 int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol);
 int AudioMixerSinkWrite(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
Index: trunk/src/VBox/Devices/Audio/DevHDA.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DevHDA.cpp	(revision 73402)
+++ trunk/src/VBox/Devices/Audio/DevHDA.cpp	(revision 73403)
@@ -2421,8 +2421,21 @@
         PAUDMIXSTREAM pMixStrm;
         rc = AudioMixerSinkCreateStream(pMixSink, pDrv->pConnector, pStreamCfg, 0 /* fFlags */, &pMixStrm);
+        LogFlowFunc(("LUN#%RU8: Created stream \"%s\" for sink, rc=%Rrc\n", pDrv->uLUN, pStreamCfg->szName, rc));
         if (RT_SUCCESS(rc))
         {
             rc = AudioMixerSinkAddStream(pMixSink, pMixStrm);
-            LogFlowFunc(("LUN#%RU8: Added \"%s\" to sink, rc=%Rrc\n", pDrv->uLUN, pStreamCfg->szName, rc));
+            LogFlowFunc(("LUN#%RU8: Added stream \"%s\" to sink, rc=%Rrc\n", pDrv->uLUN, pStreamCfg->szName, rc));
+            if (RT_SUCCESS(rc))
+            {
+                /* If this is an input stream, always set the latest (added) stream
+                 * as the recording source.
+                 * @todo Make the recording source dynamic (CFGM?). */
+                if (pStreamCfg->enmDir == PDMAUDIODIR_IN)
+                {
+                    rc = AudioMixerSinkSetRecordingSource(pMixSink, pMixStrm);
+                    LogFlowFunc(("LUN#%RU8: Recording source is now \"%s\", rc=%Rrc\n", pDrv->uLUN, pStreamCfg->szName, rc));
+                    LogRel2(("HDA: Set recording source to '%s'\n", pStreamCfg->szName));
+                }
+            }
         }
 
Index: trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DevIchAc97.cpp	(revision 73402)
+++ trunk/src/VBox/Devices/Audio/DevIchAc97.cpp	(revision 73403)
@@ -1559,8 +1559,21 @@
         PAUDMIXSTREAM pMixStrm;
         rc = AudioMixerSinkCreateStream(pMixSink, pDrv->pConnector, pStreamCfg, 0 /* fFlags */, &pMixStrm);
+        LogFlowFunc(("LUN#%RU8: Created stream \"%s\" for sink, rc=%Rrc\n", pDrv->uLUN, pStreamCfg->szName, rc));
         if (RT_SUCCESS(rc))
         {
             rc = AudioMixerSinkAddStream(pMixSink, pMixStrm);
-            LogFlowFunc(("LUN#%RU8: Created stream \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc));
+            LogFlowFunc(("LUN#%RU8: Added stream \"%s\" to sink, rc=%Rrc\n", pDrv->uLUN, pStreamCfg->szName, rc));
+            if (RT_SUCCESS(rc))
+            {
+                /* If this is an input stream, always set the latest (added) stream
+                 * as the recording source.
+                 * @todo Make the recording source dynamic (CFGM?). */
+                if (pStreamCfg->enmDir == PDMAUDIODIR_IN)
+                {
+                    rc = AudioMixerSinkSetRecordingSource(pMixSink, pMixStrm);
+                    LogFlowFunc(("LUN#%RU8: Recording source is now \"%s\", rc=%Rrc\n", pDrv->uLUN, pStreamCfg->szName, rc));
+                    LogRel2(("HDA: Set recording source to '%s'\n", pStreamCfg->szName));
+                }
+            }
         }
 
