Index: trunk/src/VBox/Devices/Audio/HDAStreamMap.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/HDAStreamMap.cpp	(revision 73529)
+++ trunk/src/VBox/Devices/Audio/HDAStreamMap.cpp	(revision 75962)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2017 Oracle Corporation
+ * Copyright (C) 2017-2018 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -35,14 +35,16 @@
 #ifdef IN_RING3
 
+static int hdaR3StreamMapSetup(PHDASTREAMMAP pMap, PPDMAUDIOPCMPROPS pProps);
+
 /**
  * Initializes a stream mapping structure according to the given PCM properties.
  *
  * @return  IPRT status code.
- * @param   pMapping            Pointer to mapping to initialize.
+ * @param   pMap                Pointer to mapping to initialize.
  * @param   pProps              Pointer to PCM properties to use for initialization.
  */
-int hdaR3StreamMapInit(PHDASTREAMMAPPING pMapping, PPDMAUDIOPCMPROPS pProps)
+int hdaR3StreamMapInit(PHDASTREAMMAP pMap, PPDMAUDIOPCMPROPS pProps)
 {
-    AssertPtrReturn(pMapping, VERR_INVALID_POINTER);
+    AssertPtrReturn(pMap, VERR_INVALID_POINTER);
     AssertPtrReturn(pProps,   VERR_INVALID_POINTER);
 
@@ -50,49 +52,29 @@
         return VERR_INVALID_PARAMETER;
 
-    hdaR3StreamMapReset(pMapping);
+    hdaR3StreamMapReset(pMap);
 
-    pMapping->paChannels = (PPDMAUDIOSTREAMCHANNEL)RTMemAlloc(sizeof(PDMAUDIOSTREAMCHANNEL) * pProps->cChannels);
-    if (!pMapping->paChannels)
-        return VERR_NO_MEMORY;
+    int rc = hdaR3StreamMapSetup(pMap, pProps);
+    if (RT_FAILURE(rc))
+        return rc;
 
-    int rc = VINF_SUCCESS;
-
-    Assert(RT_IS_POWER_OF_TWO(pProps->cBytes * 8));
-
-    /** @todo We assume all channels in a stream have the same format. */
-    PPDMAUDIOSTREAMCHANNEL pChan = pMapping->paChannels;
-    for (uint8_t i = 0; i < pProps->cChannels; i++)
-    {
-        pChan->uChannel = i;
-        pChan->cbStep   = pProps->cBytes;
-        pChan->cbFrame  = pChan->cbStep * pProps->cChannels;
-        pChan->cbFirst  = i * pChan->cbStep;
-        pChan->cbOff    = pChan->cbFirst;
-
-        int rc2 = hdaR3StreamChannelDataInit(&pChan->Data, PDMAUDIOSTREAMCHANNELDATA_FLAG_NONE);
-        if (RT_SUCCESS(rc))
-            rc = rc2;
-
-        if (RT_FAILURE(rc))
-            break;
-
-        pChan++;
-    }
-
+#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
     if (   RT_SUCCESS(rc)
         /* Create circular buffer if not created yet. */
-        && !pMapping->pCircBuf)
+        && !pMap->pCircBuf)
     {
-        rc = RTCircBufCreate(&pMapping->pCircBuf, _4K); /** @todo Make size configurable? */
+        rc = RTCircBufCreate(&pMap->pCircBuf, _4K); /** @todo Make size configurable? */
     }
+#endif
 
     if (RT_SUCCESS(rc))
     {
-        pMapping->cChannels = pProps->cChannels;
-#ifdef VBOX_WITH_HDA_AUDIO_INTERLEAVING_STREAMS_SUPPORT
-        pMapping->enmLayout = PDMAUDIOSTREAMLAYOUT_INTERLEAVED;
-#else
-        pMapping->enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
-#endif
+        pMap->cbFrameSize = pProps->cChannels * pProps->cBytes;
+
+        LogFunc(("cChannels=%RU8, cBytes=%RU8 -> cbFrameSize=%RU32\n",
+                 pProps->cChannels, pProps->cBytes, pMap->cbFrameSize));
+
+        Assert(pMap->cbFrameSize); /* Frame size must not be 0. */
+
+        pMap->enmLayout = PDMAUDIOSTREAMLAYOUT_INTERLEAVED;
     }
 
@@ -104,15 +86,17 @@
  * Destroys a given stream mapping.
  *
- * @param   pMapping            Pointer to mapping to destroy.
+ * @param   pMap            Pointer to mapping to destroy.
  */
-void hdaR3StreamMapDestroy(PHDASTREAMMAPPING pMapping)
+void hdaR3StreamMapDestroy(PHDASTREAMMAP pMap)
 {
-    hdaR3StreamMapReset(pMapping);
+    hdaR3StreamMapReset(pMap);
 
-    if (pMapping->pCircBuf)
+#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
+    if (pMap->pCircBuf)
     {
-        RTCircBufDestroy(pMapping->pCircBuf);
-        pMapping->pCircBuf = NULL;
+        RTCircBufDestroy(pMap->pCircBuf);
+        pMap->pCircBuf = NULL;
     }
+#endif
 }
 
@@ -121,25 +105,70 @@
  * Resets a given stream mapping.
  *
- * @param   pMapping            Pointer to mapping to reset.
+ * @param   pMap            Pointer to mapping to reset.
  */
-void hdaR3StreamMapReset(PHDASTREAMMAPPING pMapping)
+void hdaR3StreamMapReset(PHDASTREAMMAP pMap)
 {
-    AssertPtrReturnVoid(pMapping);
+    AssertPtrReturnVoid(pMap);
 
-    pMapping->enmLayout = PDMAUDIOSTREAMLAYOUT_UNKNOWN;
+    pMap->enmLayout = PDMAUDIOSTREAMLAYOUT_UNKNOWN;
 
-    if (pMapping->cChannels)
+    if (pMap->paMappings)
     {
-        for (uint8_t i = 0; i < pMapping->cChannels; i++)
-            hdaR3StreamChannelDataDestroy(&pMapping->paChannels[i].Data);
+        for (uint8_t i = 0; i < pMap->cMappings; i++)
+            hdaR3StreamChannelDataDestroy(&pMap->paMappings[i].Data);
 
-        AssertPtr(pMapping->paChannels);
-        RTMemFree(pMapping->paChannels);
-        pMapping->paChannels = NULL;
+        RTMemFree(pMap->paMappings);
+        pMap->paMappings = NULL;
 
-        pMapping->cChannels = 0;
+        pMap->cMappings = 0;
     }
 }
 
+
+/**
+ * Sets up a stream mapping according to the given properties / configuration.
+ *
+ * @return VBox status code, or VERR_NOT_SUPPORTED if the channel setup is not supported (yet).
+ * @param  pMap                 Pointer to mapping to set up.
+ * @param  pProps               PCM audio properties to use for lookup.
+ */
+static int hdaR3StreamMapSetup(PHDASTREAMMAP pMap, PPDMAUDIOPCMPROPS pProps)
+{
+    int rc;
+
+    /** @todo We ASSUME that all channels in a stream ...
+     *        - have the same format
+     *        - are in a consecutive order with no gaps in between
+     *        - have a simple (raw) data layout
+     *        - work in a non-striped fashion, e.g. interleaved (only on one SDn, not spread over multiple SDns) */
+    if  (   pProps->cChannels == 1  /* Mono */
+         || pProps->cChannels == 2  /* Stereo */
+         || pProps->cChannels == 4  /* Quadrophonic */
+         || pProps->cChannels == 6) /* Surround (5.1) */
+    {
+        /* For now we don't have anything other as mono / stereo channels being covered by the backends.
+         * So just set up one channel covering those and skipping the rest (like configured rear or center/LFE outputs). */
+        pMap->cMappings  = 1;
+        pMap->paMappings = (PPDMAUDIOSTREAMMAP)RTMemAlloc(sizeof(PDMAUDIOSTREAMMAP) * pMap->cMappings);
+        if (!pMap->paMappings)
+            return VERR_NO_MEMORY;
+
+        PPDMAUDIOSTREAMMAP pMapLR = &pMap->paMappings[0];
+
+        pMapLR->aID[0]  = PDMAUDIOSTREAMCHANNELID_FRONT_LEFT;
+        pMapLR->aID[1]  = PDMAUDIOSTREAMCHANNELID_FRONT_RIGHT;
+        pMapLR->cbFrame = pProps->cBytes * pProps->cChannels;
+        pMapLR->cbSize  = pProps->cBytes * 2 /* Front left + Front right channels */;
+        pMapLR->cbFirst = 0;
+        pMapLR->cbOff   = pMapLR->cbFirst;
+
+        rc = hdaR3StreamChannelDataInit(&pMapLR->Data, PDMAUDIOSTREAMCHANNELDATA_FLAG_NONE);
+        AssertRC(rc);
+    }
+    else
+        rc = VERR_NOT_SUPPORTED; /** @todo r=andy Support more setups. */
+
+    return rc;
+}
 #endif /* IN_RING3 */
 
