rendered paste bodydiff --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();
};