Index: /trunk/include/VBox/vmm/pdmaudioinline.h
===================================================================
--- /trunk/include/VBox/vmm/pdmaudioinline.h	(revision 89422)
+++ /trunk/include/VBox/vmm/pdmaudioinline.h	(revision 89423)
@@ -136,4 +136,46 @@
     }
     AssertMsgFailedReturn(("Unknown enmPath=%d\n", enmPath), "bad");
+}
+
+/**
+ * Gets the name of a channel.
+ *
+ * @returns Pointer to read-only name, "bad" if invalid input.
+ * @param   enmChannelId    The channel ID to name.
+ */
+DECLINLINE(const char *) PDMAudioChannelIdGetName(PDMAUDIOCHANNELID enmChannelId)
+{
+    switch (enmChannelId)
+    {
+        case PDMAUDIOCHANNELID_INVALID:                 return "invalid";
+        case PDMAUDIOCHANNELID_UNUSED_ZERO:             return "unused-zero";
+        case PDMAUDIOCHANNELID_UNUSED_SILENCE:          return "unused-silence";
+        case PDMAUDIOCHANNELID_UNKNOWN:                 return "unknown";
+
+        case PDMAUDIOCHANNELID_FRONT_LEFT:              return "FL";
+        case PDMAUDIOCHANNELID_FRONT_RIGHT:             return "FR";
+        case PDMAUDIOCHANNELID_FRONT_CENTER:            return "FC";
+        case PDMAUDIOCHANNELID_LFE:                     return "LFE";
+        case PDMAUDIOCHANNELID_REAR_LEFT:               return "BL";
+        case PDMAUDIOCHANNELID_REAR_RIGHT:              return "BR";
+        case PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER:    return "FLC";
+        case PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER:   return "FRC";
+        case PDMAUDIOCHANNELID_REAR_CENTER:             return "BC";
+        case PDMAUDIOCHANNELID_SIDE_LEFT:               return "SL";
+        case PDMAUDIOCHANNELID_SIDE_RIGHT:              return "SR";
+        case PDMAUDIOCHANNELID_TOP_CENTER:              return "TC";
+        case PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT:       return "TFL";
+        case PDMAUDIOCHANNELID_FRONT_CENTER_HEIGHT:     return "TFC";
+        case PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT:      return "TFR";
+        case PDMAUDIOCHANNELID_REAR_LEFT_HEIGHT:        return "TBL";
+        case PDMAUDIOCHANNELID_REAR_CENTER_HEIGHT:      return "TBC";
+        case PDMAUDIOCHANNELID_REAR_RIGHT_HEIGHT:       return "TBR";
+
+        /* no default */
+        case PDMAUDIOCHANNELID_END:
+        case PDMAUDIOCHANNELID_32BIT_HACK:
+            break;
+    }
+    AssertMsgFailedReturn(("Unknown enmChannelId=%d\n", enmChannelId), "bad");
 }
 
Index: /trunk/src/VBox/Devices/Audio/DrvHostAudioPulseAudio.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DrvHostAudioPulseAudio.cpp	(revision 89422)
+++ /trunk/src/VBox/Devices/Audio/DrvHostAudioPulseAudio.cpp	(revision 89423)
@@ -141,8 +141,4 @@
     /** Pointer to opaque PulseAudio stream. */
     pa_stream              *pStream;
-    /** Pulse sample format and attribute specification. */
-    pa_sample_spec          SampleSpec;
-    /** Pulse playback and buffer metrics. */
-    pa_buffer_attr          BufAttr;
     /** Input: Pointer to Pulse sample peek buffer. */
     const uint8_t          *pbPeekBuf;
@@ -175,4 +171,10 @@
     uint32_t                cUnderflows;
 #endif
+    /** Pulse sample format and attribute specification. */
+    pa_sample_spec          SampleSpec;
+    /** Channel map. */
+    pa_channel_map          ChannelMap;
+    /** Pulse playback and buffer metrics. */
+    pa_buffer_attr          BufAttr;
 } PULSEAUDIOSTREAM;
 /** Pointer to pulse audio stream data. */
@@ -905,5 +907,5 @@
      * Create the stream.
      */
-    pa_stream *pStream = pa_stream_new(pThis->pContext, pszName, &pStreamPA->SampleSpec, NULL /* pa_channel_map */);
+    pa_stream *pStream = pa_stream_new(pThis->pContext, pszName, &pStreamPA->SampleSpec, &pStreamPA->ChannelMap);
     if (!pStream)
     {
@@ -1022,4 +1024,71 @@
 
 /**
+ * Translates a PDM channel ID to a PA channel position.
+ *
+ * @returns PA channel position, INVALID if no mapping found.
+ */
+static pa_channel_position_t drvHstAudPaConvertChannelId(uint8_t idChannel)
+{
+    switch (idChannel)
+    {
+        case PDMAUDIOCHANNELID_FRONT_LEFT:              return PA_CHANNEL_POSITION_FRONT_LEFT;
+        case PDMAUDIOCHANNELID_FRONT_RIGHT:             return PA_CHANNEL_POSITION_FRONT_RIGHT;
+        case PDMAUDIOCHANNELID_FRONT_CENTER:            return PA_CHANNEL_POSITION_FRONT_CENTER;
+        case PDMAUDIOCHANNELID_LFE:                     return PA_CHANNEL_POSITION_LFE;
+        case PDMAUDIOCHANNELID_REAR_LEFT:               return PA_CHANNEL_POSITION_REAR_LEFT;
+        case PDMAUDIOCHANNELID_REAR_RIGHT:              return PA_CHANNEL_POSITION_REAR_RIGHT;
+        case PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER:    return PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
+        case PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER:   return PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
+        case PDMAUDIOCHANNELID_REAR_CENTER:             return PA_CHANNEL_POSITION_REAR_CENTER;
+        case PDMAUDIOCHANNELID_SIDE_LEFT:               return PA_CHANNEL_POSITION_SIDE_LEFT;
+        case PDMAUDIOCHANNELID_SIDE_RIGHT:              return PA_CHANNEL_POSITION_SIDE_RIGHT;
+        case PDMAUDIOCHANNELID_TOP_CENTER:              return PA_CHANNEL_POSITION_TOP_CENTER;
+        case PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT:       return PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
+        case PDMAUDIOCHANNELID_FRONT_CENTER_HEIGHT:     return PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
+        case PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT:      return PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
+        case PDMAUDIOCHANNELID_REAR_LEFT_HEIGHT:        return PA_CHANNEL_POSITION_TOP_REAR_LEFT;
+        case PDMAUDIOCHANNELID_REAR_CENTER_HEIGHT:      return PA_CHANNEL_POSITION_TOP_REAR_CENTER;
+        case PDMAUDIOCHANNELID_REAR_RIGHT_HEIGHT:       return PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
+        default:                                        return PA_CHANNEL_POSITION_INVALID;
+    }
+}
+
+
+/**
+ * Translates a PA channel position to a PDM channel ID.
+ *
+ * @returns PDM channel ID, UNKNOWN if no mapping found.
+ */
+static PDMAUDIOCHANNELID drvHstAudPaConvertChannelPos(pa_channel_position_t enmChannelPos)
+{
+    switch (enmChannelPos)
+    {
+        case PA_CHANNEL_POSITION_INVALID:               return PDMAUDIOCHANNELID_INVALID;
+        case PA_CHANNEL_POSITION_MONO:                  return PDMAUDIOCHANNELID_MONO;
+        case PA_CHANNEL_POSITION_FRONT_LEFT:            return PDMAUDIOCHANNELID_FRONT_LEFT;
+        case PA_CHANNEL_POSITION_FRONT_RIGHT:           return PDMAUDIOCHANNELID_FRONT_RIGHT;
+        case PA_CHANNEL_POSITION_FRONT_CENTER:          return PDMAUDIOCHANNELID_FRONT_CENTER;
+        case PA_CHANNEL_POSITION_LFE:                   return PDMAUDIOCHANNELID_LFE;
+        case PA_CHANNEL_POSITION_REAR_LEFT:             return PDMAUDIOCHANNELID_REAR_LEFT;
+        case PA_CHANNEL_POSITION_REAR_RIGHT:            return PDMAUDIOCHANNELID_REAR_RIGHT;
+        case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:  return PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER;
+        case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: return PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER;
+        case PA_CHANNEL_POSITION_REAR_CENTER:           return PDMAUDIOCHANNELID_REAR_CENTER;
+        case PA_CHANNEL_POSITION_SIDE_LEFT:             return PDMAUDIOCHANNELID_SIDE_LEFT;
+        case PA_CHANNEL_POSITION_SIDE_RIGHT:            return PDMAUDIOCHANNELID_SIDE_RIGHT;
+        case PA_CHANNEL_POSITION_TOP_CENTER:            return PDMAUDIOCHANNELID_TOP_CENTER;
+        case PA_CHANNEL_POSITION_TOP_FRONT_LEFT:        return PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT;
+        case PA_CHANNEL_POSITION_TOP_FRONT_CENTER:      return PDMAUDIOCHANNELID_FRONT_CENTER_HEIGHT;
+        case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:       return PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT;
+        case PA_CHANNEL_POSITION_TOP_REAR_LEFT:         return PDMAUDIOCHANNELID_REAR_LEFT_HEIGHT;
+        case PA_CHANNEL_POSITION_TOP_REAR_CENTER:       return PDMAUDIOCHANNELID_REAR_CENTER_HEIGHT;
+        case PA_CHANNEL_POSITION_TOP_REAR_RIGHT:        return PDMAUDIOCHANNELID_REAR_RIGHT_HEIGHT;
+        default:                                        return PDMAUDIOCHANNELID_UNKNOWN;
+    }
+}
+
+
+
+/**
  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
  */
@@ -1049,6 +1118,36 @@
     pStreamPA->SampleSpec.format   = drvHostAudioPaPropsToPulse(&pCfgReq->Props);
 
-    LogFunc(("Opening '%s', rate=%dHz, channels=%d, format=%s\n", szName, pStreamPA->SampleSpec.rate,
-             pStreamPA->SampleSpec.channels, pa_sample_format_to_string(pStreamPA->SampleSpec.format)));
+    /*
+     * Initialize the channelmap.  This may change the channel count.
+     */
+    AssertCompile(RT_ELEMENTS(pStreamPA->ChannelMap.map) >= PDMAUDIO_MAX_CHANNELS);
+    uint8_t const cSrcChannels = pStreamPA->ChannelMap.channels = PDMAudioPropsChannels(&pCfgReq->Props);
+    uintptr_t iDst = 0;
+    if (cSrcChannels == 1 && pCfgReq->Props.aidChannels[0] == PDMAUDIOCHANNELID_MONO)
+        pStreamPA->ChannelMap.map[iDst++] = PA_CHANNEL_POSITION_MONO;
+    else
+    {
+        uintptr_t iSrc;
+        for (iSrc = iDst = 0; iSrc < cSrcChannels; iSrc++)
+        {
+            pStreamPA->ChannelMap.map[iDst] = drvHstAudPaConvertChannelId(pCfgReq->Props.aidChannels[iSrc]);
+            if (pStreamPA->ChannelMap.map[iDst] != PA_CHANNEL_POSITION_INVALID)
+                iDst++;
+            else
+            {
+                LogRel2(("PulseAudio: Dropping channel #%u (%d/%s)\n", iSrc, pCfgReq->Props.aidChannels[iSrc],
+                         PDMAudioChannelIdGetName((PDMAUDIOCHANNELID)pCfgReq->Props.aidChannels[iSrc])));
+                pStreamPA->ChannelMap.channels--;
+                pStreamPA->SampleSpec.channels--;
+                PDMAudioPropsSetChannels(&pCfgAcq->Props, pStreamPA->SampleSpec.channels);
+            }
+        }
+        Assert(iDst == pStreamPA->ChannelMap.channels);
+    }
+    while (iDst < RT_ELEMENTS(pStreamPA->ChannelMap.map))
+        pStreamPA->ChannelMap.map[iDst++] = PA_CHANNEL_POSITION_INVALID;
+
+    LogFunc(("Opening '%s', rate=%dHz, channels=%d (%d), format=%s\n", szName, pStreamPA->SampleSpec.rate,
+             pStreamPA->SampleSpec.channels, cSrcChannels, pa_sample_format_to_string(pStreamPA->SampleSpec.format)));
 
     if (pa_sample_spec_valid(&pStreamPA->SampleSpec))
@@ -1064,5 +1163,5 @@
         if (pCfgReq->enmDir == PDMAUDIODIR_IN)
         {
-            pStreamPA->BufAttr.fragsize  = PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesPeriod);
+            pStreamPA->BufAttr.fragsize  = PDMAudioPropsFramesToBytes(&pCfgAcq->Props, pCfgReq->Backend.cFramesPeriod);
             LogFunc(("Requesting: BufAttr: fragsize=%RU32\n", pStreamPA->BufAttr.fragsize));
             /* (rlength, minreq and prebuf are playback only) */
@@ -1070,8 +1169,8 @@
         else
         {
-            pStreamPA->cUsLatency        = PDMAudioPropsFramesToMicro(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize);
+            pStreamPA->cUsLatency        = PDMAudioPropsFramesToMicro(&pCfgAcq->Props, pCfgReq->Backend.cFramesBufferSize);
             pStreamPA->BufAttr.tlength   = pa_usec_to_bytes(pStreamPA->cUsLatency, &pStreamPA->SampleSpec);
-            pStreamPA->BufAttr.minreq    = PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesPeriod);
-            pStreamPA->BufAttr.prebuf    = pa_usec_to_bytes(PDMAudioPropsFramesToMicro(&pCfgReq->Props,
+            pStreamPA->BufAttr.minreq    = PDMAudioPropsFramesToBytes(&pCfgAcq->Props, pCfgReq->Backend.cFramesPeriod);
+            pStreamPA->BufAttr.prebuf    = pa_usec_to_bytes(PDMAudioPropsFramesToMicro(&pCfgAcq->Props,
                                                                                        pCfgReq->Backend.cFramesPreBuffering),
                                                             &pStreamPA->SampleSpec);
@@ -1111,4 +1210,13 @@
                                                       / RT_MAX(pCfgReq->Backend.cFramesBufferSize, 1);
             }
+
+            /*
+             * Translate back the channel mapping.
+             */
+            for (iDst = 0; iDst < pStreamPA->ChannelMap.channels; iDst++)
+                 pCfgReq->Props.aidChannels[iDst] = drvHstAudPaConvertChannelPos(pStreamPA->ChannelMap.map[iDst]);
+            while (iDst < RT_ELEMENTS(pCfgReq->Props.aidChannels))
+                pCfgReq->Props.aidChannels[iDst++] = PDMAUDIOCHANNELID_INVALID;
+
             PDMAudioStrmCfgCopy(&pStreamPA->Cfg, pCfgAcq);
         }
