All pastes #1775995 Raw Edit

Something

public text v1 · immutable
#1775995 ·published 2010-02-02 18:13 UTC
rendered paste body
diff --git a/language/English/strings.xml b/language/English/strings.xml
index 6b5f59f..164f9ac 100644
--- a/language/English/strings.xml
+++ b/language/English/strings.xml
@@ -2188,5 +2188,17 @@
   <string id="34002">Wav</string>
   <string id="34003">DXVA</string>
 
+  <string id="34100">Speaker Configuration</string>
+  <string id="34101">2.0</string>
+  <string id="34102">2.1</string>
+  <string id="34103">3.0</string>
+  <string id="34104">3.1</string>
+  <string id="34105">4.0</string>
+  <string id="34106">4.1</string>
+  <string id="34107">5.0</string>
+  <string id="34108">5.1</string>
+  <string id="34109">7.0</string>
+  <string id="34110">7.1</string>
+  <!-- 34112-34200 reserved for future use -->
 
 </strings>
diff --git a/xbmc/GUISettings.cpp b/xbmc/GUISettings.cpp
index 722cb29..e040aef 100644
--- a/xbmc/GUISettings.cpp
+++ b/xbmc/GUISettings.cpp
@@ -42,6 +42,7 @@
 #include "WindowingFactory.h"
 #include "PowerManager.h"
 #include "cores/dvdplayer/DVDCodecs/Video/CrystalHD/CrystalHD.h"
+#include "utils/PCMRemap.h"
 
 using namespace std;
 
@@ -402,28 +403,35 @@ void CGUISettings::Initialize()
   audiomode.insert(make_pair(338,AUDIO_ANALOG));
   audiomode.insert(make_pair(339,AUDIO_DIGITAL));
   AddInt(3, "audiooutput.mode", 337, AUDIO_ANALOG, audiomode, SPIN_CONTROL_TEXT);
-  AddBool(4, "audiooutput.ac3passthrough", 364, true);
-  AddBool(5, "audiooutput.dtspassthrough", 254, true);
-  AddBool(6, "audiooutput.aacpassthrough", 299, false);
-  AddBool(7, "audiooutput.mp1passthrough", 300, false);
-  AddBool(8, "audiooutput.mp2passthrough", 301, false);
-  AddBool(9, "audiooutput.mp3passthrough", 302, false);
+
+  map<int,int> channelLayout;
+  for(int layout = 0; layout < PCM_MAX_LAYOUT; ++layout)
+    channelLayout.insert(make_pair(34101+layout, layout));
+  AddInt(4, "audiooutput.channellayout", 34100, PCM_LAYOUT_2_0, channelLayout, SPIN_CONTROL_TEXT);
+
+  AddBool(5, "audiooutput.ac3passthrough", 364, true);
+  AddBool(6, "audiooutput.dtspassthrough", 254, true);
+  AddBool(7, "audiooutput.aacpassthrough", 299, false);
+  AddBool(8, "audiooutput.mp1passthrough", 300, false);
+  AddBool(9, "audiooutput.mp2passthrough", 301, false);
+  AddBool(10, "audiooutput.mp3passthrough", 302, false);
+
 #ifdef __APPLE__
-  AddString(10, "audiooutput.audiodevice", 545, "Default", SPIN_CONTROL_TEXT);
+  AddString(11, "audiooutput.audiodevice", 545, "Default", SPIN_CONTROL_TEXT);
   //AddString(7, "audiooutput.passthroughdevice", 546, "S/PDIF", BUTTON_CONTROL_INPUT);
-  AddBool(11, "audiooutput.downmixmultichannel", 548, true);
+  AddBool(12, "audiooutput.downmixmultichannel", 548, true);
 #elif defined(_LINUX)
-  AddSeparator(10, "audiooutput.sep1");
-  AddString(11, "audiooutput.audiodevice", 545, "default", SPIN_CONTROL_TEXT);
-  AddString(12, "audiooutput.customdevice", 1300, "", EDIT_CONTROL_INPUT);
-  AddSeparator(13, "audiooutput.sep2");
-  AddString(14, "audiooutput.passthroughdevice", 546, "iec958", SPIN_CONTROL_TEXT);
-  AddString(15, "audiooutput.custompassthrough", 1301, "", EDIT_CONTROL_INPUT);
-  AddSeparator(16, "audiooutput.sep3");
-  AddBool(17, "audiooutput.downmixmultichannel", 548, true);
+  AddSeparator(11, "audiooutput.sep1");
+  AddString(12, "audiooutput.audiodevice", 545, "default", SPIN_CONTROL_TEXT);
+  AddString(13, "audiooutput.customdevice", 1300, "", EDIT_CONTROL_INPUT);
+  AddSeparator(14, "audiooutput.sep2");
+  AddString(15, "audiooutput.passthroughdevice", 546, "iec958", SPIN_CONTROL_TEXT);
+  AddString(16, "audiooutput.custompassthrough", 1301, "", EDIT_CONTROL_INPUT);
+  AddSeparator(17, "audiooutput.sep3");
+  //AddBool(18, "audiooutput.downmixmultichannel", 548, true);
 #elif defined(_WIN32)
-  AddString(10, "audiooutput.audiodevice", 545, "Default", SPIN_CONTROL_TEXT);
-  AddBool(11, "audiooutput.downmixmultichannel", 548, true);
+  AddString(11, "audiooutput.audiodevice", 545, "Default", SPIN_CONTROL_TEXT);
+  //AddBool(12, "audiooutput.downmixmultichannel", 548, true);
 #endif
 
   AddCategory(4, "input", 14094);
diff --git a/xbmc/cores/AudioRenderers/ALSADirectSound.cpp b/xbmc/cores/AudioRenderers/ALSADirectSound.cpp
index 0f323d9..ce56526 100644
--- a/xbmc/cores/AudioRenderers/ALSADirectSound.cpp
+++ b/xbmc/cores/AudioRenderers/ALSADirectSound.cpp
@@ -47,9 +47,11 @@ CALSADirectSound::CALSADirectSound()
   m_bIsAllocated = false;
 }
 
-bool CALSADirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
+bool CALSADirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, enum PCMChannels *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
 {
-  static int8_t ALSAChannelMap[8] =
+  enum PCMChannels *outLayout;
+
+  static enum PCMChannels ALSAChannelMap[8] =
   {
     PCM_FRONT_LEFT  , PCM_FRONT_RIGHT  ,
     PCM_BACK_LEFT   , PCM_BACK_RIGHT   ,
@@ -65,17 +67,22 @@ bool CALSADirectSound::Initialize(IAudioCallback* pCallback, const CStdString& d
 
   if (channelMap)
   {
+    /* set the input format, and get the channel layout so we know what we need to open */
+    outLayout = m_remap.SetInputFormat (iChannels, channelMap, uiBitsPerSample / 8);
     unsigned int outChannels = 0;
-    for(unsigned int ch = 0; ch < m_uiDataChannels; ++ch)
-      for(unsigned int map = 0; map < 8; ++map)
-        if (channelMap[ch] == ALSAChannelMap[map])
+    unsigned int ch = 0, map;
+    while(outLayout[ch] != PCM_INVALID)
+    {
+      for(map = 0; map < 8; ++map)
+        if (outLayout[ch] == ALSAChannelMap[map])
         {
           if (map > outChannels)
             outChannels = map;
           break;
         }
+      ++ch;
+    }
 
-    m_remap.SetInputFormat (iChannels, channelMap, uiBitsPerSample / 8);
     m_remap.SetOutputFormat(++outChannels, ALSAChannelMap);
     if (m_remap.CanRemap())
     {
@@ -155,26 +162,14 @@ bool CALSADirectSound::Initialize(IAudioCallback* pCallback, const CStdString& d
     || deviceuse == "spdif")
       deviceuse = "plug:" + deviceuse;
 
-    if(g_guiSettings.GetBool("audiooutput.downmixmultichannel"))
-    {
+    if(deviceuse == "default")
       switch(iChannels)
       {
-        case 8: deviceuse = "xbmc_71to2:'" + EscapeDevice(deviceuse) + "'"; break;
-        case 6: deviceuse = "xbmc_51to2:'" + EscapeDevice(deviceuse) + "'"; break;
-        case 5: deviceuse = "xbmc_50to2:'" + EscapeDevice(deviceuse) + "'"; break;
+        case 8: deviceuse = "surround71"; break;
+        case 6: deviceuse = "surround51"; break;
+        case 5: deviceuse = "surround50"; break;
+        case 4: deviceuse = "surround40"; break;
       }
-    }
-    else
-    {
-      if(deviceuse == "default")
-        switch(iChannels)
-        {
-          case 8: deviceuse = "surround71"; break;
-          case 6: deviceuse = "surround51"; break;
-          case 5: deviceuse = "surround50"; break;
-          case 4: deviceuse = "surround40"; break;
-        }
-    }
 
     if(deviceuse != device)
     {
diff --git a/xbmc/cores/AudioRenderers/ALSADirectSound.h b/xbmc/cores/AudioRenderers/ALSADirectSound.h
index 1a6a00c..dbffcb1 100644
--- a/xbmc/cores/AudioRenderers/ALSADirectSound.h
+++ b/xbmc/cores/AudioRenderers/ALSADirectSound.h
@@ -51,7 +51,7 @@ public:
   virtual float GetCacheTime();
   virtual float GetCacheTotal();
   CALSADirectSound();
-  virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
+  virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, enum PCMChannels *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
   virtual ~CALSADirectSound();
 
   virtual unsigned int AddPackets(const void* data, unsigned int len);
diff --git a/xbmc/cores/AudioRenderers/AudioRendererFactory.cpp b/xbmc/cores/AudioRenderers/AudioRendererFactory.cpp
index 4bb6764..c0c237f 100644
--- a/xbmc/cores/AudioRenderers/AudioRendererFactory.cpp
+++ b/xbmc/cores/AudioRenderers/AudioRendererFactory.cpp
@@ -51,7 +51,7 @@
   }                                        \
 }\
 
-IAudioRenderer* CAudioRendererFactory::Create(IAudioCallback* pCallback, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
+IAudioRenderer* CAudioRendererFactory::Create(IAudioCallback* pCallback, int iChannels, enum PCMChannels *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
 {
   IAudioRenderer* audioSink = NULL;
 
diff --git a/xbmc/cores/AudioRenderers/AudioRendererFactory.h b/xbmc/cores/AudioRenderers/AudioRendererFactory.h
index ac206ea..adb2416 100644
--- a/xbmc/cores/AudioRenderers/AudioRendererFactory.h
+++ b/xbmc/cores/AudioRenderers/AudioRendererFactory.h
@@ -31,7 +31,7 @@
 class CAudioRendererFactory
 {
 public:
-  static IAudioRenderer *Create(IAudioCallback* pCallback, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough);
+  static IAudioRenderer *Create(IAudioCallback* pCallback, int iChannels, enum PCMChannels *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough);
   static void EnumerateAudioSinks(AudioSinkList& vAudioSinks, bool passthrough);
 private:
   static IAudioRenderer *CreateFromUri(const CStdString &soundsystem);
diff --git a/xbmc/cores/AudioRenderers/CoreAudioRenderer.cpp b/xbmc/cores/AudioRenderers/CoreAudioRenderer.cpp
index c1187ef..89d0934 100644
--- a/xbmc/cores/AudioRenderers/CoreAudioRenderer.cpp
+++ b/xbmc/cores/AudioRenderers/CoreAudioRenderer.cpp
@@ -341,7 +341,7 @@ CCoreAudioRenderer::~CCoreAudioRenderer()
 if (!m_Initialized) \
 return x
 
-bool CCoreAudioRenderer::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
+bool CCoreAudioRenderer::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, enum PCMChannels *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
 {
   if (m_Initialized) // Have to clean house before we start again. TODO: Should we return failure instead?
     Deinitialize();
diff --git a/xbmc/cores/AudioRenderers/CoreAudioRenderer.h b/xbmc/cores/AudioRenderers/CoreAudioRenderer.h
index 3d4659b..6377f4c 100644
--- a/xbmc/cores/AudioRenderers/CoreAudioRenderer.h
+++ b/xbmc/cores/AudioRenderers/CoreAudioRenderer.h
@@ -105,7 +105,7 @@ class CCoreAudioRenderer : public IAudioRenderer
     virtual ~CCoreAudioRenderer();
     virtual unsigned int GetChunkLen();
     virtual float GetDelay();
-    virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
+    virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, enum PCMChannels *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
     virtual bool Deinitialize();
     virtual unsigned int AddPackets(const void* data, unsigned int len);
     virtual unsigned int GetSpace();
diff --git a/xbmc/cores/AudioRenderers/IAudioRenderer.h b/xbmc/cores/AudioRenderers/IAudioRenderer.h
index d330f83..e43805a 100644
--- a/xbmc/cores/AudioRenderers/IAudioRenderer.h
+++ b/xbmc/cores/AudioRenderers/IAudioRenderer.h
@@ -43,7 +43,7 @@ class IAudioRenderer
 public:
   IAudioRenderer() {};
   virtual ~IAudioRenderer() {};
-  virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false) = 0;
+  virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, enum PCMChannels *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false) = 0;
   virtual void UnRegisterAudioCallback() = 0;
   virtual void RegisterAudioCallback(IAudioCallback* pCallback) = 0;
   virtual float GetDelay() = 0;
diff --git a/xbmc/cores/AudioRenderers/NullDirectSound.cpp b/xbmc/cores/AudioRenderers/NullDirectSound.cpp
index d4f1ff0..400bad2 100644
--- a/xbmc/cores/AudioRenderers/NullDirectSound.cpp
+++ b/xbmc/cores/AudioRenderers/NullDirectSound.cpp
@@ -41,7 +41,7 @@ void CNullDirectSound::DoWork()
 CNullDirectSound::CNullDirectSound()
 {
 }
-bool CNullDirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
+bool CNullDirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, enum PCMChannels *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
 {
   CLog::Log(LOGERROR,"Creating a Null Audio Renderer, Check your audio settings as this should not happen");
   if (iChannels == 0)
diff --git a/xbmc/cores/AudioRenderers/NullDirectSound.h b/xbmc/cores/AudioRenderers/NullDirectSound.h
index 00d2fe4..3e6c053 100644
--- a/xbmc/cores/AudioRenderers/NullDirectSound.h
+++ b/xbmc/cores/AudioRenderers/NullDirectSound.h
@@ -41,7 +41,7 @@ public:
   virtual float GetDelay();
   virtual float GetCacheTime();
   CNullDirectSound();
-  virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
+  virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, enum PCMChannels *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
   virtual ~CNullDirectSound();
 
   virtual unsigned int AddPackets(const void* data, unsigned int len);
diff --git a/xbmc/cores/AudioRenderers/PulseAudioDirectSound.cpp b/xbmc/cores/AudioRenderers/PulseAudioDirectSound.cpp
index 172234d..ef02a5d 100644
--- a/xbmc/cores/AudioRenderers/PulseAudioDirectSound.cpp
+++ b/xbmc/cores/AudioRenderers/PulseAudioDirectSound.cpp
@@ -143,8 +143,26 @@ CPulseAudioDirectSound::CPulseAudioDirectSound()
 {
 }
 
-bool CPulseAudioDirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t* channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
+bool CPulseAudioDirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, enum PCMChannels* channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
 {
+  m_remap.Reset();
+  m_uiDataChannels = iChannels;
+  enum PCMChannels* outLayout = NULL;
+
+  if (channelMap)
+  {
+    /* set the input format, and get the channel layout so we know what we need to open */
+    outLayout = m_remap.SetInputFormat(iChannels, channelMap, uiBitsPerSample / 8);
+    enum PCMChannels *channel;
+    iChannels = 0;
+    for(channel = outLayout; *channel != PCM_INVALID; ++channel)
+      ++iChannels;
+
+    m_remap.SetOutputFormat(iChannels, outLayout);
+    if (m_uiDataChannels != (unsigned int)iChannels)
+      CLog::Log(LOGDEBUG, "CPulseAudioDirectSound::CPulseAudioDirectSound - Requested channels changed from %i to %i", m_uiDataChannels, iChannels);
+  }
+
   CLog::Log(LOGDEBUG,"PulseAudio: Opening Channels: %i - SampleRate: %i - SampleBit: %i - Resample %s - Codec %s - IsMusic %s - IsPassthrough %s - device: %s", iChannels, uiSamplesPerSec, uiBitsPerSample, bResample ? "true" : "false", strAudioCodec, bIsMusic ? "true" : "false", bPassthrough ? "true" : "false", device.c_str());
 
   bool bAudioOnAllSpeakers(false);
@@ -205,12 +223,13 @@ bool CPulseAudioDirectSound::Initialize(IAudioCallback* pCallback, const CStdStr
 
   // Build the channel map, we dont need to use PCMRemap, pulse does it for us :)
   map.channels = iChannels;
-  if (channelMap)
+  if (outLayout)
   {
     for(int ch = 0; ch < iChannels; ++ch)
     {
-      switch(channelMap[ch])
+      switch(outLayout[ch])
       {
+        case PCM_INVALID              : break;
         case PCM_FRONT_LEFT           : map.map[ch] = PA_CHANNEL_POSITION_FRONT_LEFT           ; break;
         case PCM_FRONT_RIGHT          : map.map[ch] = PA_CHANNEL_POSITION_FRONT_RIGHT          ; break;
         case PCM_FRONT_CENTER         : map.map[ch] = PA_CHANNEL_POSITION_FRONT_CENTER         ; break;
@@ -491,9 +510,18 @@ unsigned int CPulseAudioDirectSound::AddPackets(const void* data, unsigned int l
     return len;
 
   pa_threaded_mainloop_lock(m_MainLoop);
-  int length = std::min((int)GetSpace(), (int)len);
+  int length = std::min((int)GetSpace(), (int)((len / m_uiDataChannels) * m_uiChannels));
+  int rtn;
 
-  int rtn = pa_stream_write(m_Stream, data, length, NULL, 0, PA_SEEK_RELATIVE);
+  if (m_remap.CanRemap())
+  {
+    /* remap the data to the correct channels */
+    uint8_t outData[length];
+    m_remap.Remap((void *)data, outData, length / (m_uiBitsPerSample / 8) / m_uiChannels);
+    rtn = pa_stream_write(m_Stream, outData, length, NULL, 0, PA_SEEK_RELATIVE);
+  }
+  else
+    rtn = pa_stream_write(m_Stream, data, length, NULL, 0, PA_SEEK_RELATIVE);
 
 
   if (rtn < length && m_bRecentlyFlushed)
@@ -504,7 +532,7 @@ unsigned int CPulseAudioDirectSound::AddPackets(const void* data, unsigned int l
   if (m_bAutoResume)
     m_bAutoResume = !Resume();
 
-  return length - rtn;
+  return ((length - rtn) / m_uiChannels) * m_uiDataChannels;
 }
 
 float CPulseAudioDirectSound::GetCacheTime()
@@ -540,7 +568,7 @@ float CPulseAudioDirectSound::GetDelay()
 
 unsigned int CPulseAudioDirectSound::GetChunkLen()
 {
-  return m_dwPacketSize;
+  return (m_dwPacketSize / m_uiChannels) * m_uiDataChannels;
 }
 
 int CPulseAudioDirectSound::SetPlaySpeed(int iSpeed)
diff --git a/xbmc/cores/AudioRenderers/PulseAudioDirectSound.h b/xbmc/cores/AudioRenderers/PulseAudioDirectSound.h
index 06e2132..f705bd5 100644
--- a/xbmc/cores/AudioRenderers/PulseAudioDirectSound.h
+++ b/xbmc/cores/AudioRenderers/PulseAudioDirectSound.h
@@ -47,7 +47,7 @@ public:
   virtual float GetCacheTime();
   virtual float GetCacheTotal();
   CPulseAudioDirectSound();
-  virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
+  virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, enum PCMChannels *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
   virtual ~CPulseAudioDirectSound();
 
   virtual unsigned int AddPackets(const void* data, unsigned int len);
@@ -84,6 +84,7 @@ private:
   unsigned int m_uiBufferSize;
   unsigned int m_uiSamplesPerSec;
   unsigned int m_uiBitsPerSample;
+  unsigned int m_uiDataChannels;
   unsigned int m_uiChannels;
   bool m_bPause, m_bRecentlyFlushed, m_bAutoResume;
   bool m_bPassthrough;
diff --git a/xbmc/cores/AudioRenderers/Win32DirectSound.cpp b/xbmc/cores/AudioRenderers/Win32DirectSound.cpp
index 0d15b8f..b0f86aa 100644
--- a/xbmc/cores/AudioRenderers/Win32DirectSound.cpp
+++ b/xbmc/cores/AudioRenderers/Win32DirectSound.cpp
@@ -79,7 +79,7 @@ CWin32DirectSound::CWin32DirectSound() :
 {
 }
 
-bool CWin32DirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t* channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bAudioPassthrough)
+bool CWin32DirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, enum PCMChannels* channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bAudioPassthrough)
 {
   if(iChannels > DSOUND_CHANNEL_MASK_COUNT)
   {
diff --git a/xbmc/cores/AudioRenderers/Win32DirectSound.h b/xbmc/cores/AudioRenderers/Win32DirectSound.h
index 6f9014d..424ce88 100644
--- a/xbmc/cores/AudioRenderers/Win32DirectSound.h
+++ b/xbmc/cores/AudioRenderers/Win32DirectSound.h
@@ -45,7 +45,7 @@ public:
   virtual float GetCacheTime();
   virtual float GetCacheTotal();
   CWin32DirectSound();
-  virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t* channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
+  virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, enum PCMChannels* channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
   virtual ~CWin32DirectSound();
 
   virtual unsigned int AddPackets(const void* data, unsigned int len);
@@ -87,7 +87,7 @@ private:
   unsigned int m_AvgBytesPerSec;
   unsigned int m_uiBytesPerFrame;
   unsigned int m_uiSpeakerMask;
-  int8_t       m_SpeakerOrder[8];
+  enum PCMChannels m_SpeakerOrder[8];
 
   char * dserr2str(int err);
 
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h
index 28e0d22..94ead67 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h
@@ -93,7 +93,7 @@ public:
   /*
    * returns the channel mapping
    */
-  virtual int8_t* GetChannelMap() = 0;
+  virtual enum PCMChannels* GetChannelMap() = 0;
 
   /*
    * returns the samplerate for the decoded audio stream
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
index 109bf17..ae100d1 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
@@ -83,6 +83,8 @@ bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options
   if(m_pCodecContext->bits_per_coded_sample == 0)
     m_pCodecContext->bits_per_coded_sample = 16;
 
+/* for now, only set the requested layout for non-apple architecture */
+#ifdef __APPLE__
   /* if we need to downmix, do it in ffmpeg as codecs are smarter then we can ever be */
   /* wmapro does not support this */
   if(hints.codec != CODEC_ID_WMAPRO && g_guiSettings.GetBool("audiooutput.downmixmultichannel"))
@@ -91,6 +93,7 @@ bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options
     // below is required or center channel is missing with VC1 content under OSX.
     m_pCodecContext->request_channels = 2;
   }
+#endif
 
   if( hints.extradata && hints.extrasize > 0 )
   {
@@ -249,45 +252,112 @@ int CDVDAudioCodecFFmpeg::GetBitsPerSample()
   return 16;
 }
 
-int8_t* CDVDAudioCodecFFmpeg::GetChannelMap()
+enum PCMChannels* CDVDAudioCodecFFmpeg::GetChannelMap()
 {
-  /* the side channels for < 7.0 are mapped to the back intentionally, do not change this! */
-  static int8_t map[14][8] =
-  {
-    {/* MONO         */ PCM_FRONT_CENTER                                                                                                                                          },
-    {/* STEREO       */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT                                                                                                                           },
-    {/* 2_1          */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_BACK_CENTER                                                                                                          },
-    {/* SURROUND     */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER                                                                                                         },
-    {/* 4POINT0      */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_CENTER                                                                                        },
-    {/* 2_2          */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_BACK_LEFT   , PCM_BACK_RIGHT                                                                                         },
-    {/* QUAD         */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_BACK_LEFT   , PCM_BACK_RIGHT                                                                                         },
-    {/* 5POINT0      */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT    , PCM_BACK_RIGHT                                                                      },
-    {/* 5POINT1      */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, PCM_BACK_LEFT , PCM_BACK_RIGHT                                                      },
-    {/* 5POINT0_BACK */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT    , PCM_BACK_RIGHT                                                                      },
-    {/* 5POINT1_BACK */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, PCM_BACK_LEFT , PCM_BACK_RIGHT                                                      },
-    {/* 7POINT0      */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT    , PCM_BACK_RIGHT, PCM_SIDE_LEFT , PCM_SIDE_RIGHT                                      },
-    {/* 7POINT1      */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, PCM_BACK_LEFT , PCM_BACK_RIGHT, PCM_SIDE_LEFT            , PCM_SIDE_RIGHT           },
-    {/* 7POINT1_WIDE */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, PCM_BACK_LEFT , PCM_BACK_RIGHT, PCM_FRONT_LEFT_OF_CENTER , PCM_FRONT_RIGHT_OF_CENTER}
-  };
-
-  switch(m_pCodecContext->channel_layout &~ CH_LAYOUT_STEREO_DOWNMIX)
+  int index = 0;
+  if (m_pCodecContext->channel_layout && CH_FRONT_LEFT           ) m_channelMap[index++] = PCM_FRONT_LEFT           ;
+  if (m_pCodecContext->channel_layout && CH_FRONT_RIGHT          ) m_channelMap[index++] = PCM_FRONT_RIGHT          ;
+  if (m_pCodecContext->channel_layout && CH_FRONT_CENTER         ) m_channelMap[index++] = PCM_FRONT_CENTER         ;
+  if (m_pCodecContext->channel_layout && CH_LOW_FREQUENCY        ) m_channelMap[index++] = PCM_LOW_FREQUENCY        ;
+  if (m_pCodecContext->channel_layout && CH_BACK_LEFT            ) m_channelMap[index++] = PCM_BACK_LEFT            ;
+  if (m_pCodecContext->channel_layout && CH_BACK_RIGHT           ) m_channelMap[index++] = PCM_BACK_RIGHT           ;
+  if (m_pCodecContext->channel_layout && CH_FRONT_LEFT_OF_CENTER ) m_channelMap[index++] = PCM_FRONT_LEFT_OF_CENTER ;
+  if (m_pCodecContext->channel_layout && CH_FRONT_RIGHT_OF_CENTER) m_channelMap[index++] = PCM_FRONT_RIGHT_OF_CENTER;
+  if (m_pCodecContext->channel_layout && CH_BACK_CENTER          ) m_channelMap[index++] = PCM_BACK_CENTER          ;
+  if (m_pCodecContext->channel_layout && CH_SIDE_LEFT            ) m_channelMap[index++] = PCM_SIDE_LEFT            ;
+  if (m_pCodecContext->channel_layout && CH_SIDE_RIGHT           ) m_channelMap[index++] = PCM_SIDE_RIGHT           ;
+  if (m_pCodecContext->channel_layout && CH_TOP_CENTER           ) m_channelMap[index++] = PCM_TOP_CENTER           ;
+  if (m_pCodecContext->channel_layout && CH_TOP_FRONT_LEFT       ) m_channelMap[index++] = PCM_TOP_FRONT_LEFT       ;
+  if (m_pCodecContext->channel_layout && CH_TOP_FRONT_CENTER     ) m_channelMap[index++] = PCM_TOP_FRONT_CENTER     ;
+  if (m_pCodecContext->channel_layout && CH_TOP_FRONT_RIGHT      ) m_channelMap[index++] = PCM_TOP_FRONT_RIGHT      ;
+  if (m_pCodecContext->channel_layout && CH_TOP_BACK_LEFT        ) m_channelMap[index++] = PCM_TOP_BACK_LEFT        ;
+  if (m_pCodecContext->channel_layout && CH_TOP_BACK_CENTER      ) m_channelMap[index++] = PCM_TOP_BACK_CENTER      ;
+  if (m_pCodecContext->channel_layout && CH_TOP_BACK_RIGHT       ) m_channelMap[index++] = PCM_TOP_BACK_RIGHT       ;
+
+  /* if there is less channels in the map then advertised, we need to fix it */
+  if (index < m_pCodecContext->channels)
   {
-    case CH_LAYOUT_MONO        : return map[ 0];
-    case CH_LAYOUT_STEREO      : return map[ 1];
-    case CH_LAYOUT_2_1         : return map[ 2];
-    case CH_LAYOUT_SURROUND    : return map[ 3];
-    case CH_LAYOUT_4POINT0     : return map[ 4];
-    case CH_LAYOUT_2_2         : return map[ 5];
-    case CH_LAYOUT_QUAD        : return map[ 6];
-    case CH_LAYOUT_5POINT0     : return map[ 7];
-    case CH_LAYOUT_5POINT1     : return map[ 8];
-    case CH_LAYOUT_5POINT0_BACK: return map[ 9];
-    case CH_LAYOUT_5POINT1_BACK: return map[10];
-    case CH_LAYOUT_7POINT0     : return map[11];
-    case CH_LAYOUT_7POINT1     : return map[12];
-    case CH_LAYOUT_7POINT1_WIDE: return map[13];
-    default:
+    CLog::Log(LOGINFO, "CDVDAudioCodecFFmpeg::GetChannelMap - FFmpeg did not repot the channel layout properly, trying to guess");
+
+    index = 0;
+    switch(m_pCodecContext->codec_id)
+    {
+      case CODEC_ID_FLAC:
+        switch(m_pCodecContext->channels)
+        {
+          case 1:
+            m_channelMap[index++] = PCM_FRONT_CENTER;
+            break;
+
+          case 2:
+            m_channelMap[index++] = PCM_FRONT_LEFT;
+            m_channelMap[index++] = PCM_FRONT_RIGHT;
+            break;
+
+          case 3:
+            m_channelMap[index++] = PCM_FRONT_LEFT;
+            m_channelMap[index++] = PCM_FRONT_RIGHT;
+            m_channelMap[index++] = PCM_FRONT_CENTER;
+            break;
+
+          case 4:
+            m_channelMap[index++] = PCM_FRONT_LEFT;
+            m_channelMap[index++] = PCM_FRONT_RIGHT;
+            m_channelMap[index++] = PCM_BACK_LEFT;
+            m_channelMap[index++] = PCM_BACK_RIGHT;
+            break;
+
+          case 5:
+            m_channelMap[index++] = PCM_FRONT_LEFT;
+            m_channelMap[index++] = PCM_FRONT_RIGHT;
+            m_channelMap[index++] = PCM_FRONT_CENTER;
+            m_channelMap[index++] = PCM_SIDE_LEFT;
+            m_channelMap[index++] = PCM_SIDE_RIGHT;
+            break;
+
+          case 6:
+            m_channelMap[index++] = PCM_FRONT_LEFT;
+            m_channelMap[index++] = PCM_FRONT_RIGHT;
+            m_channelMap[index++] = PCM_FRONT_CENTER;
+            m_channelMap[index++] = PCM_LOW_FREQUENCY;
+            m_channelMap[index++] = PCM_SIDE_LEFT;
+            m_channelMap[index++] = PCM_SIDE_RIGHT;
+            break;
+
+          case 7:
+            m_channelMap[index++] = PCM_FRONT_LEFT;
+            m_channelMap[index++] = PCM_FRONT_RIGHT;
+            m_channelMap[index++] = PCM_FRONT_CENTER;
+            m_channelMap[index++] = PCM_BACK_LEFT;
+            m_channelMap[index++] = PCM_BACK_RIGHT;
+            m_channelMap[index++] = PCM_SIDE_LEFT;
+            m_channelMap[index++] = PCM_SIDE_RIGHT;
+            break;
+
+          case 8:
+            m_channelMap[index++] = PCM_FRONT_LEFT;
+            m_channelMap[index++] = PCM_FRONT_RIGHT;
+            m_channelMap[index++] = PCM_FRONT_CENTER;
+            m_channelMap[index++] = PCM_LOW_FREQUENCY;
+            m_channelMap[index++] = PCM_BACK_LEFT;
+            m_channelMap[index++] = PCM_BACK_RIGHT;
+            m_channelMap[index++] = PCM_SIDE_LEFT;
+            m_channelMap[index++] = PCM_SIDE_RIGHT;
+            break;
+        }
+        break;
+
+      default:;
+    }
+
+    if (index == 0)
+    {
+      CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::GetChannelMap - Unable to guess a channel layout, please report this to XBMC and submit a sample file");
       return NULL;
+    }
+    return m_channelMap;
   }
-}
 
+  m_channelMap[index] = PCM_INVALID;
+  return m_channelMap;
+}
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h
index 03409f6..c343841 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h
@@ -36,7 +36,7 @@ public:
   virtual int GetData(BYTE** dst);
   virtual void Reset();
   virtual int GetChannels();
-  virtual int8_t *GetChannelMap();
+  virtual enum PCMChannels *GetChannelMap();
   virtual int GetSampleRate();
   virtual int GetBitsPerSample();
   virtual const char* GetName() { return "FFmpeg"; }
@@ -46,6 +46,7 @@ protected:
   AVCodecContext* m_pCodecContext;
   AVAudioConvert* m_pConvert;;
   enum SampleFormat m_iSampleFormat;
+  enum PCMChannels m_channelMap[PCM_MAX_CH + 1];
 
   BYTE *m_pBuffer1;
   int   m_iBufferSize1;
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.cpp
index 31d2d3b..403d5b9 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.cpp
@@ -103,7 +103,7 @@ bool CDVDAudioCodecLibFaad::SyncStream()
   return false;
 }
 
-int8_t* CDVDAudioCodecLibFaad::GetChannelMap()
+enum PCMChannels* CDVDAudioCodecLibFaad::GetChannelMap()
 {
   for(int i = 0; i < m_iSourceChannels; ++i)
   {
@@ -247,7 +247,11 @@ bool CDVDAudioCodecLibFaad::OpenDecoder()
 
     // modify some stuff here
     pConfiguration->outputFormat = FAAD_FMT_16BIT; // already default
+#ifdef __APPLE__
     pConfiguration->downMatrix   = g_guiSettings.GetBool("audiooutput.downmixmultichannel") ? 1 : 0;
+#else
+    pConfiguration->downMatrix   = 0;
+#endif
 
     m_dll.faacDecSetConfiguration(m_pHandle, pConfiguration);
 
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.h b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.h
index 840a796..a4b483e 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.h
@@ -38,7 +38,7 @@ public:
   virtual int GetData(BYTE** dst);
   virtual void Reset();
   virtual int GetChannels()        { return m_iSourceChannels; }
-  virtual int8_t* GetChannelMap();
+  virtual enum PCMChannels* GetChannelMap();
   virtual int GetSampleRate()      { return m_iSourceSampleRate; }
   virtual int GetBitsPerSample()   { return 16; }
   virtual const char* GetName()    { return "libfaad"; }
@@ -53,7 +53,7 @@ private:
 
   int m_iSourceSampleRate;
   int m_iSourceChannels;
-  int8_t m_pChannelMap[64];
+  enum PCMChannels m_pChannelMap[64];
   int m_iSourceBitrate;
 
   bool m_bInitializedDecoder;
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibMad.h b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibMad.h
index 99271cf..9dfa6ca 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibMad.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibMad.h
@@ -38,7 +38,7 @@ public:
   virtual int GetData(BYTE** dst);
   virtual void Reset();
   virtual int GetChannels()        { return m_iSourceChannels; }
-  virtual int8_t* GetChannelMap()  { static int8_t map[2] = {PCM_FRONT_LEFT, PCM_FRONT_RIGHT}; return map; }
+  virtual enum PCMChannels* GetChannelMap()  { static enum PCMChannels map[2] = {PCM_FRONT_LEFT, PCM_FRONT_RIGHT}; return map; }
   virtual int GetSampleRate()      { return m_iSourceSampleRate; }
   virtual int GetBitsPerSample()   { return 16; }
   virtual const char* GetName()    { return "libmad"; }
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.h
index db1f07c..921dbf5 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.h
@@ -39,7 +39,7 @@ public:
   virtual int GetData(BYTE** dst);
   virtual void Reset();
   virtual int GetChannels();
-  virtual int8_t *GetChannelMap() { static int8_t map[2] = {PCM_FRONT_LEFT, PCM_FRONT_RIGHT}; return map; }
+  virtual enum PCMChannels *GetChannelMap() { static enum PCMChannels map[2] = {PCM_FRONT_LEFT, PCM_FRONT_RIGHT}; return map; }
   virtual int GetSampleRate();
   virtual int GetBitsPerSample();
   virtual bool NeedPassthrough() { return true; }
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.cpp
index bfe293b..fd96b2f 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.cpp
@@ -293,10 +293,10 @@ int CDVDAudioCodecPcm::GetChannels()
   return m_iOutputChannels;
 }
 
-int8_t* CDVDAudioCodecPcm::GetChannelMap()
+enum PCMChannels* CDVDAudioCodecPcm::GetChannelMap()
 {
   /* ? = probarbly wrong, just a guess */
-  static int8_t map[8][8] =
+  static enum PCMChannels map[8][8] =
   {
     /* MONO   */ {PCM_FRONT_CENTER                                                                                                                                                },
     /* STEREO */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT                                                                                                                                 },
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.h b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.h
index 8adbf7a..b7d8f74 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.h
@@ -34,7 +34,7 @@ public:
   virtual int GetData(BYTE** dst);
   virtual void Reset();
   virtual int GetChannels();
-  virtual int8_t* GetChannelMap();
+  virtual enum PCMChannels* GetChannelMap();
   virtual int GetSampleRate();
   virtual int GetBitsPerSample();
   virtual const char* GetName()  { return "pcm"; }
diff --git a/xbmc/cores/dvdplayer/DVDPlayerAudio.h b/xbmc/cores/dvdplayer/DVDPlayerAudio.h
index 93778a3..934ccc8 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerAudio.h
+++ b/xbmc/cores/dvdplayer/DVDPlayerAudio.h
@@ -54,7 +54,7 @@ typedef struct stDVDAudioFrame
   unsigned int size;
 
   int channels;
-  int8_t *channel_map;
+  enum PCMChannels *channel_map;
   int bits_per_sample;
   int sample_rate;
   bool passthrough;
diff --git a/xbmc/cores/paplayer/PAPlayer.h b/xbmc/cores/paplayer/PAPlayer.h
index 1c7133b..3507e85 100644
--- a/xbmc/cores/paplayer/PAPlayer.h
+++ b/xbmc/cores/paplayer/PAPlayer.h
@@ -179,7 +179,7 @@ private:
 
   // format (this should be stored/retrieved from the audio device object probably)
   unsigned int     m_channelCount[2];
-  int8_t*          m_channelMap[2];
+  enum PCMChannels*m_channelMap[2];
   unsigned int     m_sampleRate[2];
   unsigned int     m_bitsPerSample[2];
   unsigned int     m_BytesPerSecond;
diff --git a/xbmc/utils/PCMRemap.cpp b/xbmc/utils/PCMRemap.cpp
index 8e7345a..5e6b156 100644
--- a/xbmc/utils/PCMRemap.cpp
+++ b/xbmc/utils/PCMRemap.cpp
@@ -22,20 +22,176 @@
 #include <cstdlib>
 #include <string.h>
 #include <stdio.h>
+#include <math.h>
 
 #include "PCMRemap.h"
 #include "utils/log.h"
+#include "GUISettings.h"
+
+static enum PCMChannels PCMLayoutMap[PCM_MAX_LAYOUT][PCM_MAX_CH + 1] =
+{
+  /* 2.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_INVALID},
+  /* 2.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID},
+  /* 3.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_INVALID},
+  /* 3.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, PCM_INVALID},
+  /* 4.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_INVALID},
+  /* 4.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, PCM_INVALID},
+  /* 5.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_INVALID},
+  /* 5.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID},
+  /* 7.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_SIDE_LEFT, PCM_SIDE_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_INVALID},
+  /* 7.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_SIDE_LEFT, PCM_SIDE_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID}
+};
+
+static const char* PCMChannelName[PCM_MAX_CH] =
+{
+  "FL",
+  "FR",
+  "CE",
+  "LFE",
+  "BL",
+  "BR",
+  "FLOC",
+  "FROC",
+  "BC",
+  "SL",
+  "SR",
+  "TFL",
+  "TFR",
+  "TFC",
+  "TC",
+  "TBL",
+  "TBR",
+  "TBC",
+};
+
+static const char* PCMLayoutName[PCM_MAX_LAYOUT] =
+{
+  "2.0",
+  "2.1",
+  "3.0",
+  "3.1",
+  "4.0",
+  "4.1",
+  "5.0",
+  "5.1",
+  "7.0",
+  "7.1"
+};
+
+/*
+  map missing output into channel @ volume level
+  the order of this table is important, mix tables can not depend on channels that have not been defined yet
+  eg, FC can only be mixed into FL, FR as they are the only channels that have been defined
+*/
+#define PCM_MAX_MIX 3
+static struct PCMMapInfo PCMDownmixTable[PCM_MAX_CH][PCM_MAX_MIX] =
+{
+  /* PCM_FRONT_LEFT */
+  {
+    {PCM_INVALID}
+  },
+  /* PCM_FRONT_RIGHT */
+  {
+    {PCM_INVALID}
+  },
+  /* PCM_FRONT_CENTER */
+  {
+    {PCM_FRONT_LEFT           , 0.5},
+    {PCM_FRONT_RIGHT          , 0.5},
+    {PCM_INVALID}
+  },
+  /* PCM_LOW_FREQUENCY */
+  {
+    {PCM_FRONT_LEFT           , 1.0},
+    {PCM_FRONT_RIGHT          , 1.0},
+    {PCM_INVALID}
+  },
+  /* PCM_BACK_LEFT */
+  {
+    {PCM_FRONT_LEFT           , 0.3},
+    {PCM_INVALID}
+  },
+  /* PCM_BACK_RIGHT */
+  {
+    {PCM_FRONT_RIGHT          , 0.3},
+    {PCM_INVALID}
+  },
+  /* PCM_FRONT_LEFT_OF_CENTER */
+  {
+    {PCM_FRONT_LEFT           , 0.5},
+    {PCM_FRONT_CENTER         , 0.5},
+    {PCM_INVALID}
+  },
+  /* PCM_FRONT_RIGHT_OF_CENTER */
+  {
+    {PCM_FRONT_RIGHT          , 0.5},
+    {PCM_FRONT_CENTER         , 0.5},
+    {PCM_INVALID}
+  },
+  /* PCM_BACK_CENTER */
+  {
+    {PCM_BACK_LEFT            , 0.5},
+    {PCM_BACK_RIGHT           , 0.5},
+    {PCM_INVALID}
+  },
+  /* PCM_SIDE_LEFT */
+  {
+    {PCM_BACK_LEFT            , 1.0},
+    {PCM_INVALID}
+  },
+  /* PCM_SIDE_RIGHT */
+  {
+    {PCM_BACK_RIGHT           , 1.0},
+    {PCM_INVALID}
+  },
+  /* PCM_TOP_FRONT_LEFT */
+  {
+    {PCM_FRONT_LEFT           , 0.5},
+    {PCM_INVALID}
+  },
+  /* PCM_TOP_FRONT_RIGHT */
+  {
+    {PCM_FRONT_RIGHT          , 0.5},
+    {PCM_INVALID}
+  },
+  /* PCM_TOP_FRONT_CENTER */
+  {
+    {PCM_TOP_FRONT_LEFT       , 0.5},
+    {PCM_TOP_FRONT_RIGHT      , 0.5},
+    {PCM_INVALID}
+  },
+  /* PCM_TOP_CENTER */
+  {
+    {PCM_TOP_FRONT_LEFT       , 0.5},
+    {PCM_TOP_FRONT_RIGHT      , 0.5},
+    {PCM_INVALID}
+  },
+  /* PCM_TOP_BACK_LEFT */
+  {
+    {PCM_BACK_LEFT            , 0.5},
+    {PCM_INVALID}
+  },
+  /* PCM_TOP_BACK_RIGHT */
+  {
+    {PCM_BACK_LEFT            , 0.5},
+    {PCM_INVALID}
+  },
+  /* PCM_TOP_BACK_CENTER */
+  {
+    {PCM_TOP_BACK_LEFT        , 0.5},
+    {PCM_TOP_BACK_RIGHT       , 0.5},
+    {PCM_INVALID}
+  }
+};
 
 CPCMRemap::CPCMRemap() :
-  m_inSet   (false),
-  m_outSet  (false),
+  m_inSet       (false),
+  m_outSet      (false),
   m_inChannels  (0),
   m_outChannels (0),
-  m_inSampleSize(0),
-  m_inMap   (NULL ),
-  m_outMap  (NULL ),
-  m_chLookup(NULL )
+  m_inSampleSize(0)
 {
+  Dispose();
 }
 
 CPCMRemap::~CPCMRemap()
@@ -45,8 +201,36 @@ CPCMRemap::~CPCMRemap()
 
 void CPCMRemap::Dispose()
 {
-  delete[] m_chLookup;
-  m_chLookup = NULL;
+  memset(m_useable  , 0          , sizeof(m_useable  ));
+  memset(m_lookupMap, PCM_INVALID, sizeof(m_lookupMap));
+}
+
+/* resolves the channels recursively and returns the new index of tablePtr */
+struct PCMMapInfo* CPCMRemap::ResolveChannel(enum PCMChannels channel, float level, struct PCMMapInfo *tablePtr)
+{
+  if (channel == PCM_INVALID) return tablePtr;
+
+  /* if its a 1 to 1 mapping, return */
+  if (m_useable[channel])
+  {
+    tablePtr->channel = channel;
+    tablePtr->level   = level;
+
+    ++tablePtr;
+    tablePtr->channel = PCM_INVALID;
+    return tablePtr;
+  }
+
+  /* loop through the downmix children and resolve them */
+  struct PCMMapInfo *info;
+  for(info = PCMDownmixTable[channel]; info->channel != PCM_INVALID; ++info)
+  {
+    /* calculate the level based on our full volume */
+    float  l = (info->level * (level / 100)) * 100;
+    tablePtr = ResolveChannel(info->channel, l, tablePtr);
+  }
+
+  return tablePtr;
 }
 
 /*
@@ -55,27 +239,59 @@ void CPCMRemap::Dispose()
 */
 void CPCMRemap::BuildMap()
 {
-  unsigned int in_ch, out_ch;
-
   if (!m_inSet || !m_outSet) return;
   Dispose();
 
-  delete[] m_chLookup;
-  m_chLookup = new int8_t[m_inChannels];
-  for(in_ch = 0; in_ch < m_inChannels; ++in_ch)
+  unsigned int in_ch, out_ch;
+
+  /* figure out what channels we have and can use */
+  for(enum PCMChannels *chan = PCMLayoutMap[m_channelLayout]; *chan != PCM_INVALID; ++chan)
   {
     for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
-    {
-      if (m_outMap[out_ch] == m_inMap[in_ch])
+      if (m_outMap[out_ch] == *chan)
       {
-        m_chLookup[in_ch] = out_ch;
+        m_useable[*chan] = true;
         break;
       }
+  }
+
+  /* resolve all the channels */
+  struct PCMMapInfo table[PCM_MAX_CH + 1], *info, *dst;
+  for(in_ch = 0; in_ch < m_inChannels; ++in_ch) {
+    ResolveChannel(m_inMap[in_ch], 1.0f, table);
+    for(info = table; info->channel != PCM_INVALID; ++info)
+    {
+      /* get the table, find the end of the table */
+      for(dst = m_lookupMap[info->channel]; dst->channel != PCM_INVALID; ++dst) {}
+
+      /* append it to the table */
+      dst->channel = m_inMap[in_ch];
+      dst->level   = info->level;
+
+      /* terminate the table */
+      ++dst;
+      dst->channel = PCM_INVALID;
     }
   }
+  
+  /* build our reverse lookup table */
+  for(in_ch = 0; in_ch < m_inChannels; ++in_ch)
+    m_inLookup[m_inMap[in_ch]] = in_ch;
+
+  /* output the final map for debugging */
+  for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
+  {
+    CStdString s = "", f;
+    for(dst = m_lookupMap[m_outMap[out_ch]]; dst->channel != PCM_INVALID; ++dst)
+    {
+      f.Format("%s(%f) ",  PCMChannelName[dst->channel], dst->level);
+      s += f;
+    }
+    CLog::Log(LOGDEBUG, "CPCMRemap: %s = %s\n", PCMChannelName[m_outMap[out_ch]], s.c_str());
+  }
 }
 
-void CPCMRemap::DumpMap(CStdString info, unsigned int channels, int8_t *channelMap)
+void CPCMRemap::DumpMap(CStdString info, unsigned int channels, enum PCMChannels *channelMap)
 {
   if (channelMap == NULL)
   {
@@ -83,12 +299,10 @@ void CPCMRemap::DumpMap(CStdString info, unsigned int channels, int8_t *channelM
     return;
   }
 
-  CStdString mapping = "", convert;
+  CStdString mapping = "";
   for(unsigned int i = 0; i < channels; ++i)
-  {
-    convert.Format("%d", channelMap[i]);
-    mapping += ((i == 0) ? "" : ",") + convert;
-  }
+    mapping += ((i == 0) ? "" : ",") + (CStdString)PCMChannelName[channelMap[i]];
+
   CLog::Log(LOGINFO, "CPCMRemap: %s channel map: %s\n", info.c_str(), mapping.c_str());
 }
 
@@ -98,28 +312,41 @@ void CPCMRemap::Reset()
   m_outMap = NULL;
   m_inSet  = false;
   m_outSet = false;
+  Dispose();
 }
 
-/* sets the input format */
-void CPCMRemap::SetInputFormat(unsigned int channels, int8_t *channelMap, unsigned int sampleSize)
+/* sets the input format, and returns the requested channel layout */
+enum PCMChannels *CPCMRemap::SetInputFormat(unsigned int channels, enum PCMChannels *channelMap, unsigned int sampleSize)
 {
   m_inChannels   = channels;
   m_inMap        = channelMap;
   m_inSampleSize = sampleSize;
   m_inSet        = channelMap != NULL;
 
-  DumpMap("Input", channels, channelMap);
+  /* fix me later */
+  assert(sampleSize == 2);
+
+  /* get the audio layout, and count the channels in it */
+  m_channelLayout  = (enum PCMLayout)g_guiSettings.GetInt("audiooutput.channellayout");
+  if (m_channelLayout >= PCM_MAX_LAYOUT) m_channelLayout = PCM_LAYOUT_2_0;
+
+  CLog::Log(LOGINFO, "CPCMRemap: Channel Layout: %s\n", PCMLayoutName[m_channelLayout]);
+  m_layoutMap      = PCMLayoutMap[m_channelLayout];
+
+  DumpMap("I", channels, channelMap);
   BuildMap();
+
+  return m_layoutMap;
 }
 
-/* sets the output format required */
-void CPCMRemap::SetOutputFormat(unsigned int channels, int8_t *channelMap)
+/* sets the output format supported by the audio renderer */
+void CPCMRemap::SetOutputFormat(unsigned int channels, enum PCMChannels *channelMap)
 {
   m_outChannels   = channels;
   m_outMap        = channelMap;
   m_outSet        = channelMap != NULL;
 
-  DumpMap("Output", channels, channelMap);
+  DumpMap("O", channels, channelMap);
   BuildMap();
 }
 
@@ -140,12 +367,23 @@ void CPCMRemap::Remap(void *data, void *out, unsigned int samples)
   memset(out, 0, samples * (m_inSampleSize * m_outChannels));
   for(i = 0; i < samples; ++i)
   {
-    for(ch = 0; ch < m_inChannels; ++ch)
+    for(ch = 0; ch < m_outChannels; ++ch)
     {
-      src = insample  + (ch             * m_inSampleSize);
-      dst = outsample + (m_chLookup[ch] * m_inSampleSize);
-      memcpy(dst, src, m_inSampleSize);
+      struct PCMMapInfo *info;
+      float value = 0;
+      int   div   = 0;
+
+      for(info = m_lookupMap[m_outMap[ch]]; info->channel != PCM_INVALID; ++info)
+      {
+        src    = insample + m_inLookup[info->channel] * m_inSampleSize;
+        value += (float)(*(int16_t*)src) * info->level;
+        ++div;
+      }
+      value /= (float)div;
+      dst = outsample + ch * m_inSampleSize;
+      *((int16_t*)dst) = (int16_t)((value > 0.0) ? floor(value + 0.5) : ceil(value - 0.5));
     }
+
     insample  += m_inSampleSize * m_inChannels;
     outsample += m_inSampleSize * m_outChannels;
   }
diff --git a/xbmc/utils/PCMRemap.h b/xbmc/utils/PCMRemap.h
index aef6f69..5324c46 100644
--- a/xbmc/utils/PCMRemap.h
+++ b/xbmc/utils/PCMRemap.h
@@ -25,45 +25,76 @@
 #include <stdint.h>
 #include "guilib/StdString.h"
 
-#define PCM_FRONT_LEFT            0
-#define PCM_FRONT_RIGHT           1
-#define PCM_FRONT_CENTER          2
-#define PCM_LOW_FREQUENCY         3
-#define PCM_BACK_LEFT             4
-#define PCM_BACK_RIGHT            5
-#define PCM_FRONT_LEFT_OF_CENTER  6
-#define PCM_FRONT_RIGHT_OF_CENTER 7
-#define PCM_BACK_CENTER           8
-#define PCM_SIDE_LEFT             9
-#define PCM_SIDE_RIGHT            10
-#define PCM_TOP_CENTER            11
-#define PCM_TOP_FRONT_LEFT        12
-#define PCM_TOP_FRONT_CENTER      13
-#define PCM_TOP_FRONT_RIGHT       14
-#define PCM_TOP_BACK_LEFT         15
-#define PCM_TOP_BACK_CENTER       16
-#define PCM_TOP_BACK_RIGHT        17
+#define PCM_MAX_CH 18
+enum PCMChannels
+{
+  PCM_INVALID = -1,
+  PCM_FRONT_LEFT,
+  PCM_FRONT_RIGHT,
+  PCM_FRONT_CENTER,
+  PCM_LOW_FREQUENCY,
+  PCM_BACK_LEFT,
+  PCM_BACK_RIGHT,
+  PCM_FRONT_LEFT_OF_CENTER,
+  PCM_FRONT_RIGHT_OF_CENTER,
+  PCM_BACK_CENTER,
+  PCM_SIDE_LEFT,
+  PCM_SIDE_RIGHT,
+  PCM_TOP_FRONT_LEFT,
+  PCM_TOP_FRONT_RIGHT,
+  PCM_TOP_FRONT_CENTER,
+  PCM_TOP_CENTER,
+  PCM_TOP_BACK_LEFT,
+  PCM_TOP_BACK_RIGHT,
+  PCM_TOP_BACK_CENTER
+};
+
+#define PCM_MAX_LAYOUT 10
+enum PCMLayout
+{
+  PCM_LAYOUT_2_0 = 0,
+  PCM_LAYOUT_2_1,
+  PCM_LAYOUT_3_0,
+  PCM_LAYOUT_3_1,
+  PCM_LAYOUT_4_0,
+  PCM_LAYOUT_4_1,
+  PCM_LAYOUT_5_0,
+  PCM_LAYOUT_5_1,
+  PCM_LAYOUT_7_0,
+  PCM_LAYOUT_7_1
+};
+
+struct PCMMapInfo
+{
+  enum  PCMChannels channel;
+  float level;
+};
 
 class CPCMRemap
 {
 protected:
-  bool         m_inSet     , m_outSet;
-  unsigned int m_inChannels, m_outChannels;
-  unsigned int m_inSampleSize;
-  int8_t      *m_inMap     , *m_outMap;
-  int8_t      *m_chLookup;
+  bool              m_inSet, m_outSet;
+  enum PCMLayout    m_channelLayout;
+  unsigned int      m_inChannels, m_outChannels;
+  unsigned int      m_inSampleSize;
+  enum PCMChannels *m_inMap, *m_outMap, *m_layoutMap;
+
+  bool              m_useable  [PCM_MAX_CH];
+  struct PCMMapInfo m_lookupMap[PCM_MAX_CH + 1][PCM_MAX_CH + 1];
+  int8_t            m_inLookup [PCM_MAX_CH];
 
-  void BuildMap();
-  void DumpMap(CStdString info, int unsigned channels, int8_t *channelMap);
-  void Dispose();
+  struct PCMMapInfo* ResolveChannel(enum PCMChannels channel, float level, struct PCMMapInfo *tablePtr);
+  void               BuildMap();
+  void               DumpMap(CStdString info, int unsigned channels, enum PCMChannels *channelMap);
+  void               Dispose();
 public:
 
   CPCMRemap();
   ~CPCMRemap();
 
   void Reset();
-  void SetInputFormat (unsigned int channels, int8_t *channelMap, unsigned int sampleSize);
-  void SetOutputFormat(unsigned int channels, int8_t *channelMap);
+  enum PCMChannels *SetInputFormat (unsigned int channels, enum PCMChannels *channelMap, unsigned int sampleSize);
+  void SetOutputFormat(unsigned int channels, enum PCMChannels *channelMap);
   void Remap(void *data, void *out, unsigned int samples);
   bool CanRemap();
 };