Index: trunk/src/VBox/Devices/Audio/DrvHostAudioAlsa.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostAudioAlsa.cpp	(revision 89470)
+++ trunk/src/VBox/Devices/Audio/DrvHostAudioAlsa.cpp	(revision 89471)
@@ -418,4 +418,44 @@
 
 /**
+ * Maps a PDM channel ID to an ASLA channel map position.
+ */
+static unsigned int drvHstAudAlsaPdmChToAlsa(PDMAUDIOCHANNELID enmId, uint8_t cChannels)
+{
+    switch (enmId)
+    {
+        case PDMAUDIOCHANNELID_UNKNOWN:                 return SND_CHMAP_UNKNOWN;
+        case PDMAUDIOCHANNELID_UNUSED_ZERO:             return SND_CHMAP_NA;
+        case PDMAUDIOCHANNELID_UNUSED_SILENCE:          return SND_CHMAP_NA;
+
+        case PDMAUDIOCHANNELID_FRONT_LEFT:              return SND_CHMAP_FL;
+        case PDMAUDIOCHANNELID_FRONT_RIGHT:             return SND_CHMAP_FR;
+        case PDMAUDIOCHANNELID_FRONT_CENTER:            return cChannels == 1 ? SND_CHMAP_MONO : SND_CHMAP_FC;
+        case PDMAUDIOCHANNELID_LFE:                     return SND_CHMAP_LFE;
+        case PDMAUDIOCHANNELID_REAR_LEFT:               return SND_CHMAP_RL;
+        case PDMAUDIOCHANNELID_REAR_RIGHT:              return SND_CHMAP_RR;
+        case PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER:    return SND_CHMAP_FLC;
+        case PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER:   return SND_CHMAP_FRC;
+        case PDMAUDIOCHANNELID_REAR_CENTER:             return SND_CHMAP_RC;
+        case PDMAUDIOCHANNELID_SIDE_LEFT:               return SND_CHMAP_SL;
+        case PDMAUDIOCHANNELID_SIDE_RIGHT:              return SND_CHMAP_SR;
+        case PDMAUDIOCHANNELID_TOP_CENTER:              return SND_CHMAP_TC;
+        case PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT:       return SND_CHMAP_TFL;
+        case PDMAUDIOCHANNELID_FRONT_CENTER_HEIGHT:     return SND_CHMAP_TFC;
+        case PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT:      return SND_CHMAP_TFR;
+        case PDMAUDIOCHANNELID_REAR_LEFT_HEIGHT:        return SND_CHMAP_TRL;
+        case PDMAUDIOCHANNELID_REAR_CENTER_HEIGHT:      return SND_CHMAP_TRC;
+        case PDMAUDIOCHANNELID_REAR_RIGHT_HEIGHT:       return SND_CHMAP_TRR;
+
+        case PDMAUDIOCHANNELID_INVALID:
+        case PDMAUDIOCHANNELID_END:
+        case PDMAUDIOCHANNELID_32BIT_HACK:
+            break;
+    }
+    AssertFailed();
+    return SND_CHMAP_NA;
+}
+
+
+/**
  * Sets the hardware parameters of an ALSA stream.
  *
@@ -451,5 +491,5 @@
     AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set access type: %s\n", snd_strerror(err)), err);
 
-    /* Set the format, frequency and channel count. */
+    /* Set the format and frequency. */
     err = snd_pcm_hw_params_set_format(hPCM, pHWParms, enmAlsaFmt);
     AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set audio format to %d: %s\n", enmAlsaFmt, snd_strerror(err)), err);
@@ -461,15 +501,41 @@
     pCfgAcq->Props.uHz = uFreq;
 
-    unsigned int cChannels = PDMAudioPropsChannels(&pCfgReq->Props);
+    /* Channel count currently does not change with the mapping translations,
+       as ALSA can express both silent and unknown channel positions. */
+    union
+    {
+        snd_pcm_chmap_t Map;
+        unsigned int    padding[1 + PDMAUDIO_MAX_CHANNELS];
+    } u;
+    uint8_t      aidChannels[PDMAUDIO_MAX_CHANNELS];
+    unsigned int cChannels = u.Map.channels = PDMAudioPropsChannels(&pCfgReq->Props);
+    unsigned int iDst      = 0;
+    for (unsigned int iSrc = 0; iSrc < cChannels; iSrc++)
+    {
+        uint8_t const idSrc = pCfgReq->Props.aidChannels[iSrc];
+        aidChannels[iDst] = idSrc;
+        u.Map.pos[iDst]   = drvHstAudAlsaPdmChToAlsa((PDMAUDIOCHANNELID)idSrc, cChannels);
+        iDst++;
+    }
+    u.Map.channels = cChannels = iDst;
+    for (; iDst < PDMAUDIO_MAX_CHANNELS; iDst++)
+    {
+        aidChannels[iDst] = PDMAUDIOCHANNELID_INVALID;
+        u.Map.pos[iDst]   = SND_CHMAP_NA;
+    }
+
     err = snd_pcm_hw_params_set_channels_near(hPCM, pHWParms, &cChannels);
     AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set number of channels to %d\n", PDMAudioPropsChannels(&pCfgReq->Props)),
                           err);
-    if (cChannels != PDMAudioPropsChannels(&pCfgReq->Props))
-    {
+    if (cChannels == PDMAudioPropsChannels(&pCfgReq->Props))
+        memcpy(pCfgAcq->Props.aidChannels, aidChannels, sizeof(pCfgAcq->Props.aidChannels));
+    else
+    {
+        LogRel2(("ALSA: Requested %u channels, got %u\n", u.Map.channels, cChannels));
         AssertLogRelMsgReturn(cChannels > 0 && cChannels <= PDMAUDIO_MAX_CHANNELS,
                               ("ALSA: Unsupported channel count: %u (requested %d)\n",
                                cChannels, PDMAudioPropsChannels(&pCfgReq->Props)), -ERANGE);
         PDMAudioPropsSetChannels(&pCfgAcq->Props, (uint8_t)cChannels);
-        /** @todo Can we somehow guess channel IDs? */
+        /** @todo Can we somehow guess channel IDs? snd_pcm_get_chmap? */
     }
 
@@ -521,4 +587,15 @@
              PDMAudioPropsHz(&pCfgAcq->Props), pCfgAcq->Backend.cFramesPeriod, pCfgAcq->Backend.cFramesBufferSize,
              PDMAudioPropsChannels(&pCfgAcq->Props), enmAlsaFmt));
+
+    /*
+     * Channel config (not fatal).
+     */
+    if (PDMAudioPropsChannels(&pCfgAcq->Props) == PDMAudioPropsChannels(&pCfgReq->Props))
+    {
+        err = snd_pcm_set_chmap(hPCM, &u.Map);
+        if (err < 0)
+            LogRel2(("ALSA: snd_pcm_set_chmap failed: %s (%d)\n", snd_strerror(err), err));
+    }
+
     return 0;
 }
@@ -572,5 +649,5 @@
                 {
                     /*
-                     * Configure software stream parameters and we're done.
+                     * Configure software stream parameters.
                      */
                     rc = alsaStreamSetSWParams(hPCM, pCfgReq, pCfgAcq);
Index: trunk/src/VBox/Devices/Audio/DrvHostAudioAlsaStubs.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostAudioAlsaStubs.cpp	(revision 89470)
+++ trunk/src/VBox/Devices/Audio/DrvHostAudioAlsaStubs.cpp	(revision 89471)
@@ -95,4 +95,5 @@
            (pcm, buffer, size))
 PROXY_STUB(snd_pcm_resume, int, (snd_pcm_t *pcm), (pcm))
+PROXY_STUB(snd_pcm_set_chmap, int, (snd_pcm_t *pcm, snd_pcm_chmap_t const *map), (pcm, map))
 PROXY_STUB(snd_pcm_state, snd_pcm_state_t, (snd_pcm_t *pcm), (pcm))
 PROXY_STUB(snd_pcm_state_name, const char *, (snd_pcm_state_t state), (state))
@@ -109,4 +110,10 @@
         ret = (int)*availp;
     return ret;
+}
+
+static int fallback_snd_pcm_set_chmap(snd_pcm_t *pcm, snd_pcm_chmap_t const *map)
+{
+    RT_NOREF(pcm, map);
+    return 0;
 }
 
@@ -208,4 +215,5 @@
     ELEMENT(snd_pcm_prepare),
     ELEMENT(snd_pcm_resume),
+    ELEMENT_FALLBACK(snd_pcm_set_chmap),
     ELEMENT(snd_pcm_state),
     ELEMENT(snd_pcm_state_name),
Index: trunk/src/VBox/Devices/Audio/DrvHostAudioAlsaStubs.h
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostAudioAlsaStubs.h	(revision 89470)
+++ trunk/src/VBox/Devices/Audio/DrvHostAudioAlsaStubs.h	(revision 89471)
@@ -25,15 +25,32 @@
 #include <alsa/version.h>
 
+#define VBOX_ALSA_MAKE_VER(a,b,c)   ( ((a) << 24) | ((b) << 16) | (a) )
+#define VBOX_ALSA_VER               VBOX_ALSA_MAKE_VER(SND_LIB_MAJOR, SND_LIB_MINOR, SND_LIB_SUBMINOR)
+
 RT_C_DECLS_BEGIN
 extern int audioLoadAlsaLib(void);
 
-#if (((SND_LIB_MAJOR) << 16) | ((SND_LIB_MAJOR) << 8) | (SND_LIB_SUBMINOR)) >= 0x10000 /* was added in 1.0.0 */
+#if VBOX_ALSA_VER < VBOX_ALSA_MAKE_VER(1,0,0)   /* added in 1.0.0 */
 extern int  snd_pcm_avail_delay(snd_pcm_t *, snd_pcm_sframes_t *, snd_pcm_sframes_t *);
 #endif
 
-#if (((SND_LIB_MAJOR) << 16) | ((SND_LIB_MAJOR) << 8) | (SND_LIB_SUBMINOR)) >= 0x1000e /* was added in 1.0.14a */
+#if VBOX_ALSA_VER < VBOX_ALSA_MAKE_VER(1,0,14)  /* added in 1.0.14a */
 extern int  snd_device_name_hint(int, const char *, void ***);
 extern int  snd_device_name_free_hint(void **);
 extern char *snd_device_name_get_hint(const void *, const char *);
+#endif
+
+#if VBOX_ALSA_VER < VBOX_ALSA_MAKE_VER(1,0,27)  /* added in 1.0.27 */
+enum snd_pcm_chmap_position { SND_CHMAP_UNKNOWN = 0, SND_CHMAP_NA, SND_CHMAP_MONO, SND_CHMAP_FL, SND_CHMAP_FR,
+    SND_CHMAP_RL,  SND_CHMAP_RR,   SND_CHMAP_FC,   SND_CHMAP_LFE,  SND_CHMAP_SL,  SND_CHMAP_SR,  SND_CHMAP_RC,
+    SND_CHMAP_FLC, SND_CHMAP_FRC,  SND_CHMAP_RLC,  SND_CHMAP_RRC,  SND_CHMAP_FLW, SND_CHMAP_FRW, SND_CHMAP_FLH,
+    SND_CHMAP_FCH, SND_CHMAP_FRH,  SND_CHMAP_TC,   SND_CHMAP_TFL,  SND_CHMAP_TFR, SND_CHMAP_TFC, SND_CHMAP_TRL,
+    SND_CHMAP_TRR, SND_CHMAP_TRC,  SND_CHMAP_TFLC, SND_CHMAP_TFRC, SND_CHMAP_TSL, SND_CHMAP_TSR, SND_CHMAP_LLFE,
+    SND_CHMAP_RLFE, SND_CHMAP_BC,  SND_CHMAP_BLC,  SND_CHMAP_BRC };
+typedef struct snd_pcm_chmap
+{
+    unsigned int channels, pos[0];
+} snd_pcm_chmap_t;
+extern int snd_pcm_set_chmap(snd_pcm_t *, const snd_pcm_chmap_t *);
 #endif
 
Index: trunk/src/VBox/Devices/Audio/DrvHostAudioAlsaStubsMangling.h
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostAudioAlsaStubsMangling.h	(revision 89470)
+++ trunk/src/VBox/Devices/Audio/DrvHostAudioAlsaStubsMangling.h	(revision 89471)
@@ -44,4 +44,5 @@
 #define snd_pcm_readi                           ALSA_MANGLER(snd_pcm_readi)
 #define snd_pcm_resume                          ALSA_MANGLER(snd_pcm_resume)
+#define snd_pcm_set_chmap                       ALSA_MANGLER(snd_pcm_set_chmap)
 #define snd_pcm_start                           ALSA_MANGLER(snd_pcm_start)
 #define snd_pcm_state                           ALSA_MANGLER(snd_pcm_state)
