aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRainer Hochecker <fernetmenta@online.de>2013-12-08 11:28:39 -0800
committerRainer Hochecker <fernetmenta@online.de>2013-12-08 11:28:39 -0800
commitc530e0d2052744eebe4fd8481b3a46a8bef3fd68 (patch)
tree0639e0193f028fc1eefb15d0d53b12c59de14359
parent9382b857e4b393210f815957426447fb3fc80753 (diff)
parentd4766829253c5e9f9996a55974f9ea2c503e771d (diff)
Merge pull request #3744 from FernetMenta/aefixes
Aefixes
-rw-r--r--system/settings/settings.xml8
-rw-r--r--xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp32
-rw-r--r--xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.cpp5
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp122
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkALSA.h15
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp117
-rw-r--r--xbmc/cores/AudioEngine/Utils/AEChannelInfo.cpp23
7 files changed, 235 insertions, 87 deletions
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index 4b69b388a4..1a3aca4805 100644
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -2222,7 +2222,13 @@
<level>2</level>
<default>false</default>
<dependencies>
- <dependency type="visible" setting="audiooutput.channels" operator="!is">1</dependency>
+ <dependency type="visible">
+ <or>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.channels">audiooutput.stereoupmix</condition>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.passthrough">audiooutput.stereoupmix</condition>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.ac3passthrough">audiooutput.stereoupmix</condition>
+ </or>
+ </dependency>
</dependencies>
<control type="toggle" />
</setting>
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
index a3a61647f6..c977c37b6b 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
@@ -865,6 +865,14 @@ void CActiveAE::Configure(AEAudioFormat *desiredFmt)
initSink = true;
m_stats.Reset(m_sinkFormat.m_sampleRate);
m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::VOLUME, &m_volume, sizeof(float));
+
+ // limit buffer size in case of sink returns large buffer
+ unsigned int buffertime = (m_sinkFormat.m_frames*1000) / m_sinkFormat.m_sampleRate;
+ if (buffertime > 80)
+ {
+ CLog::Log(LOGWARNING, "ActiveAE::%s - sink returned large buffer of %d ms, reducing to 80 ms", __FUNCTION__, buffertime);
+ m_sinkFormat.m_frames = 80 * m_sinkFormat.m_sampleRate / 1000;
+ }
}
if (m_silenceBuffers)
@@ -877,8 +885,6 @@ void CActiveAE::Configure(AEAudioFormat *desiredFmt)
if (m_streams.empty())
{
inputFormat = m_sinkFormat;
- inputFormat.m_channelLayout = m_sinkRequestFormat.m_channelLayout;
- inputFormat.m_channelLayout.ResolveChannels(m_sinkFormat.m_channelLayout);
inputFormat.m_dataFormat = AE_FMT_FLOAT;
inputFormat.m_frameSize = inputFormat.m_channelLayout.Count() *
(CAEUtil::DataFormatToBits(inputFormat.m_dataFormat) >> 3);
@@ -967,8 +973,6 @@ void CActiveAE::Configure(AEAudioFormat *desiredFmt)
else
{
outputFormat = m_sinkFormat;
- outputFormat.m_channelLayout = m_sinkRequestFormat.m_channelLayout;
- outputFormat.m_channelLayout.ResolveChannels(m_sinkFormat.m_channelLayout);
outputFormat.m_dataFormat = AE_FMT_FLOAT;
outputFormat.m_frameSize = outputFormat.m_channelLayout.Count() *
(CAEUtil::DataFormatToBits(outputFormat.m_dataFormat) >> 3);
@@ -997,6 +1001,7 @@ void CActiveAE::Configure(AEAudioFormat *desiredFmt)
// create buffer pool
(*it)->m_inputBuffers = new CActiveAEBufferPool((*it)->m_format);
(*it)->m_inputBuffers->Create(MAX_CACHE_LEVEL*1000);
+ (*it)->m_streamSpace = (*it)->m_format.m_frameSize * (*it)->m_format.m_frames;
}
if (initSink && (*it)->m_resampleBuffers)
{
@@ -1325,7 +1330,7 @@ void CActiveAE::ApplySettingsToFormat(AEAudioFormat &format, AudioSettings &sett
if (m_settings.config == AE_CONFIG_FIXED || (settings.stereoupmix && format.m_channelLayout.Count() <= 2))
format.m_channelLayout = stdLayout;
else
- format.m_channelLayout.ResolveChannels(stdLayout);;
+ format.m_channelLayout.ResolveChannels(stdLayout);
}
// don't change from multi to stereo in AUTO mode
else if ((settings.config == AE_CONFIG_AUTO) &&
@@ -1999,7 +2004,7 @@ void CActiveAE::LoadSettings()
m_settings.channels = (m_sink.GetDeviceType(m_settings.device) == AE_DEVTYPE_IEC958) ? AE_CH_LAYOUT_2_0 : CSettings::Get().GetInt("audiooutput.channels");
m_settings.samplerate = CSettings::Get().GetInt("audiooutput.samplerate");
- m_settings.stereoupmix = (m_settings.channels > AE_CH_LAYOUT_2_0) ? CSettings::Get().GetBool("audiooutput.stereoupmix") : false;
+ m_settings.stereoupmix = IsSettingVisible("audiooutput.stereoupmix") ? CSettings::Get().GetBool("audiooutput.stereoupmix") : false;
m_settings.normalizelevels = CSettings::Get().GetBool("audiooutput.normalizelevels");
m_settings.passthrough = m_settings.config == AE_CONFIG_FIXED ? false : CSettings::Get().GetBool("audiooutput.passthrough");
@@ -2146,6 +2151,21 @@ bool CActiveAE::IsSettingVisible(const std::string &settingId)
m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) == AE_DEVTYPE_HDMI)
return true;
}
+ else if (settingId == "audiooutput.stereoupmix")
+ {
+ if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) != AE_DEVTYPE_IEC958)
+ {
+ if (CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0)
+ return true;
+ }
+ else
+ {
+ if (m_sink.HasPassthroughDevice() &&
+ CSettings::Get().GetBool("audiooutput.passthrough") &&
+ CSettings::Get().GetBool("audiooutput.ac3passthrough"))
+ return true;
+ }
+ }
return false;
}
diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.cpp b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.cpp
index d57dd5a3a7..71458ee68c 100644
--- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.cpp
+++ b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.cpp
@@ -530,6 +530,11 @@ bool CCoreAudioAE::IsSettingVisible(const std::string &settingId)
else
return false;
}
+ else if (settingId == "audiooutput.stereoupmix")
+ {
+ if (CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0)
+ return true;
+ }
return true;
}
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
index 4f63535d2c..f1e5401ecd 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
@@ -45,12 +45,24 @@ static enum AEChannel ALSAChannelMap[ALSA_MAX_CHANNELS + 1] = {
AE_CH_NULL
};
-static enum AEChannel ALSAChannelMapWide[ALSA_MAX_CHANNELS + 1] = {
+static enum AEChannel ALSAChannelMap51Wide[ALSA_MAX_CHANNELS + 1] = {
AE_CH_FL , AE_CH_FR , AE_CH_SL , AE_CH_SR , AE_CH_FC , AE_CH_LFE , AE_CH_BL , AE_CH_BR ,
AE_CH_UNKNOWN1, AE_CH_UNKNOWN2, AE_CH_UNKNOWN3, AE_CH_UNKNOWN4, AE_CH_UNKNOWN5, AE_CH_UNKNOWN6, AE_CH_UNKNOWN7, AE_CH_UNKNOWN8, /* for p16v devices */
AE_CH_NULL
};
+static enum AEChannel ALSAChannelMap71Wide[ALSA_MAX_CHANNELS + 1] = {
+ AE_CH_FLOC , AE_CH_FROC , AE_CH_BL , AE_CH_BR , AE_CH_FC , AE_CH_LFE , AE_CH_FL , AE_CH_FR ,
+ AE_CH_UNKNOWN1, AE_CH_UNKNOWN2, AE_CH_UNKNOWN3, AE_CH_UNKNOWN4, AE_CH_UNKNOWN5, AE_CH_UNKNOWN6, AE_CH_UNKNOWN7, AE_CH_UNKNOWN8, /* for p16v devices */
+ AE_CH_NULL
+};
+
+static enum AEChannel ALSAChannelMapPassthrough[ALSA_MAX_CHANNELS + 1] = {
+ AE_CH_RAW , AE_CH_RAW , AE_CH_RAW , AE_CH_RAW , AE_CH_RAW , AE_CH_RAW , AE_CH_RAW , AE_CH_RAW ,
+ AE_CH_UNKNOWN1, AE_CH_UNKNOWN2, AE_CH_UNKNOWN3, AE_CH_UNKNOWN4, AE_CH_UNKNOWN5, AE_CH_UNKNOWN6, AE_CH_UNKNOWN7, AE_CH_UNKNOWN8, /* for p16v devices */
+ AE_CH_NULL
+};
+
static unsigned int ALSASampleRateList[] =
{
5512,
@@ -87,25 +99,37 @@ CAESinkALSA::~CAESinkALSA()
Deinitialize();
}
-inline CAEChannelInfo CAESinkALSA::GetChannelLayout(AEAudioFormat format)
+inline CAEChannelInfo CAESinkALSA::GetChannelLayout(AEAudioFormat format, unsigned int maxChannels)
{
+ enum AEChannel* channelMap = ALSAChannelMap;
unsigned int count = 0;
- if (format.m_dataFormat == AE_FMT_AC3 ||
- format.m_dataFormat == AE_FMT_DTS ||
- format.m_dataFormat == AE_FMT_EAC3)
- count = 2;
+ if (format.m_dataFormat == AE_FMT_AC3 ||
+ format.m_dataFormat == AE_FMT_DTS ||
+ format.m_dataFormat == AE_FMT_EAC3)
+ {
+ count = 2;
+ channelMap = ALSAChannelMapPassthrough;
+ }
else if (format.m_dataFormat == AE_FMT_TRUEHD ||
format.m_dataFormat == AE_FMT_DTSHD)
- count = 8;
+ {
+ count = 8;
+ channelMap = ALSAChannelMapPassthrough;
+ }
else
{
// According to CEA-861-D only RL and RR are known. In case of a format having SL and SR channels
// but no BR BL channels, we use the wide map in order to open only the num of channels really
// needed.
- enum AEChannel* channelMap = ALSAChannelMap;
if (format.m_channelLayout.HasChannel(AE_CH_SL) && !format.m_channelLayout.HasChannel(AE_CH_BL))
- channelMap = ALSAChannelMapWide;
+ {
+ channelMap = ALSAChannelMap51Wide;
+ }
+ else if (maxChannels >= 8 && format.m_channelLayout.HasChannel(AE_CH_FLOC) && !format.m_channelLayout.HasChannel(AE_CH_SL))
+ {
+ channelMap = ALSAChannelMap71Wide;
+ }
for (unsigned int c = 0; c < 8; ++c)
for (unsigned int i = 0; i < format.m_channelLayout.Count(); ++i)
if (format.m_channelLayout[i] == channelMap[c])
@@ -116,8 +140,12 @@ inline CAEChannelInfo CAESinkALSA::GetChannelLayout(AEAudioFormat format)
}
CAEChannelInfo info;
- for (unsigned int i = 0; i < count; ++i)
- info += ALSAChannelMap[i];
+ for (unsigned int i = 0; i < count && i < maxChannels+1; ++i)
+ info += channelMap[i];
+
+ CLog::Log(LOGDEBUG, "CAESinkALSA::GetChannelLayout - Input Channel Count: %d Output Channel Count: %d", format.m_channelLayout.Count(), count);
+ CLog::Log(LOGDEBUG, "CAESinkALSA::GetChannelLayout - Requested Layout: %s", std::string(format.m_channelLayout).c_str());
+ CLog::Log(LOGDEBUG, "CAESinkALSA::GetChannelLayout - Got Layout: %s", std::string(info).c_str());
return info;
}
@@ -143,20 +171,22 @@ void CAESinkALSA::GetAESParams(AEAudioFormat format, std::string& params)
bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device)
{
- CAEChannelInfo channelLayout;
+ CAEChannelInfo channelLayout = GetChannelLayout(format, 8);
m_initDevice = device;
m_initFormat = format;
+ ALSAConfig inconfig, outconfig;
+ inconfig.format = format.m_dataFormat;
+ inconfig.sampleRate = format.m_sampleRate;
+ inconfig.channels = channelLayout.Count();
/* if we are raw, correct the data format */
if (AE_IS_RAW(format.m_dataFormat))
{
- channelLayout = GetChannelLayout(format);
- format.m_dataFormat = AE_FMT_S16NE;
- m_passthrough = true;
+ inconfig.format = AE_FMT_S16NE;
+ m_passthrough = true;
}
else
{
- channelLayout = GetChannelLayout(format);
m_passthrough = false;
}
#if defined(HAS_LIBAMCODEC)
@@ -167,14 +197,12 @@ bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device)
}
#endif
- if (channelLayout.Count() == 0)
+ if (inconfig.channels == 0)
{
CLog::Log(LOGERROR, "CAESinkALSA::Initialize - Unable to open the requested channel layout");
return false;
}
- format.m_channelLayout = channelLayout;
-
AEDeviceType devType = AEDeviceTypeFromName(device);
std::string AESParams;
@@ -189,7 +217,7 @@ bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device)
snd_config_t *config;
snd_config_copy(&config, snd_config);
- if (!OpenPCMDevice(device, AESParams, channelLayout.Count(), &m_pcm, config))
+ if (!OpenPCMDevice(device, AESParams, inconfig.channels, &m_pcm, config))
{
CLog::Log(LOGERROR, "CAESinkALSA::Initialize - failed to initialize device \"%s\"", device.c_str());
snd_config_delete(config);
@@ -205,13 +233,26 @@ bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device)
/* free the sound config */
snd_config_delete(config);
- if (!InitializeHW(format) || !InitializeSW(format))
+ if (!InitializeHW(inconfig, outconfig) || !InitializeSW(outconfig))
return false;
// we want it blocking
snd_pcm_nonblock(m_pcm, 0);
snd_pcm_prepare (m_pcm);
+ if (m_passthrough && inconfig.channels != outconfig.channels)
+ {
+ CLog::Log(LOGINFO, "CAESinkALSA::Initialize - could not open required number of channels");
+ return false;
+ }
+ // adjust format to the configuration we got
+ format.m_channelLayout = GetChannelLayout(format, outconfig.channels);
+ format.m_sampleRate = outconfig.sampleRate;
+ format.m_frames = outconfig.periodSize;
+ format.m_frameSize = outconfig.frameSize;
+ format.m_frameSamples = outconfig.periodSize * outconfig.channels;
+ format.m_dataFormat = outconfig.format;
+
m_format = format;
m_formatSampleRateMul = 1.0 / (double)m_format.m_sampleRate;
@@ -255,7 +296,7 @@ snd_pcm_format_t CAESinkALSA::AEFormatToALSAFormat(const enum AEDataFormat forma
}
}
-bool CAESinkALSA::InitializeHW(AEAudioFormat &format)
+bool CAESinkALSA::InitializeHW(const ALSAConfig &inconfig, ALSAConfig &outconfig)
{
snd_pcm_hw_params_t *hw_params;
@@ -265,35 +306,35 @@ bool CAESinkALSA::InitializeHW(AEAudioFormat &format)
snd_pcm_hw_params_any(m_pcm, hw_params);
snd_pcm_hw_params_set_access(m_pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
- unsigned int sampleRate = format.m_sampleRate;
- unsigned int channelCount = format.m_channelLayout.Count();
+ unsigned int sampleRate = inconfig.sampleRate;
+ unsigned int channelCount = inconfig.channels;
snd_pcm_hw_params_set_rate_near (m_pcm, hw_params, &sampleRate, NULL);
snd_pcm_hw_params_set_channels_near(m_pcm, hw_params, &channelCount);
/* ensure we opened X channels or more */
- if (format.m_channelLayout.Count() > channelCount)
+ if (inconfig.channels > channelCount)
{
CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Unable to open the required number of channels");
}
- /* update the channelLayout to what we managed to open */
- format.m_channelLayout.Reset();
- for (unsigned int i = 0; i < channelCount; ++i)
- format.m_channelLayout += ALSAChannelMap[i];
+ /* update outconfig */
+ outconfig.channels = channelCount;
+
+ snd_pcm_format_t fmt = AEFormatToALSAFormat(inconfig.format);
+ outconfig.format = inconfig.format;
- snd_pcm_format_t fmt = AEFormatToALSAFormat(format.m_dataFormat);
if (fmt == SND_PCM_FORMAT_UNKNOWN)
{
/* if we dont support the requested format, fallback to float */
- format.m_dataFormat = AE_FMT_FLOAT;
- fmt = SND_PCM_FORMAT_FLOAT;
+ fmt = SND_PCM_FORMAT_FLOAT;
+ outconfig.format = AE_FMT_FLOAT;
}
/* try the data format */
if (snd_pcm_hw_params_set_format(m_pcm, hw_params, fmt) < 0)
{
/* if the chosen format is not supported, try each one in decending order */
- CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Your hardware does not support %s, trying other formats", CAEUtil::DataFormatToStr(format.m_dataFormat));
+ CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Your hardware does not support %s, trying other formats", CAEUtil::DataFormatToStr(outconfig.format));
for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1))
{
if (AE_IS_RAW(i) || i == AE_FMT_MAX)
@@ -322,8 +363,8 @@ bool CAESinkALSA::InitializeHW(AEAudioFormat &format)
}
/* record that the format fell back to X */
- format.m_dataFormat = i;
- CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Using data format %s", CAEUtil::DataFormatToStr(format.m_dataFormat));
+ outconfig.format = i;
+ CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Using data format %s", CAEUtil::DataFormatToStr(outconfig.format));
break;
}
@@ -418,10 +459,9 @@ bool CAESinkALSA::InitializeHW(AEAudioFormat &format)
CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Got: periodSize %lu, bufferSize %lu", periodSize, bufferSize);
/* set the format parameters */
- format.m_sampleRate = sampleRate;
- format.m_frames = periodSize;
- format.m_frameSamples = periodSize * format.m_channelLayout.Count();
- format.m_frameSize = snd_pcm_frames_to_bytes(m_pcm, 1);
+ outconfig.sampleRate = sampleRate;
+ outconfig.periodSize = periodSize;
+ outconfig.frameSize = snd_pcm_frames_to_bytes(m_pcm, 1);
m_bufferSize = (unsigned int)bufferSize;
m_timeout = std::ceil((double)(bufferSize * 1000) / (double)sampleRate);
@@ -431,7 +471,7 @@ bool CAESinkALSA::InitializeHW(AEAudioFormat &format)
return true;
}
-bool CAESinkALSA::InitializeSW(AEAudioFormat &format)
+bool CAESinkALSA::InitializeSW(const ALSAConfig &inconfig)
{
snd_pcm_sw_params_t *sw_params;
snd_pcm_uframes_t boundary;
@@ -444,7 +484,7 @@ bool CAESinkALSA::InitializeSW(AEAudioFormat &format)
snd_pcm_sw_params_set_silence_threshold(m_pcm, sw_params, 0);
snd_pcm_sw_params_get_boundary (sw_params, &boundary);
snd_pcm_sw_params_set_silence_size (m_pcm, sw_params, boundary);
- snd_pcm_sw_params_set_avail_min (m_pcm, sw_params, format.m_frames);
+ snd_pcm_sw_params_set_avail_min (m_pcm, sw_params, inconfig.periodSize);
if (snd_pcm_sw_params(m_pcm, sw_params) < 0)
{
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h
index d920fdb022..2fafacc7b5 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h
@@ -52,7 +52,7 @@ public:
static void EnumerateDevicesEx(AEDeviceInfoList &list, bool force = false);
private:
- CAEChannelInfo GetChannelLayout(AEAudioFormat format);
+ CAEChannelInfo GetChannelLayout(AEAudioFormat format, unsigned int maxChannels);
void GetAESParams(const AEAudioFormat format, std::string& params);
void HandleError(const char* name, int err);
@@ -66,10 +66,19 @@ private:
snd_pcm_t *m_pcm;
int m_timeout;
+ struct ALSAConfig
+ {
+ unsigned int sampleRate;
+ unsigned int periodSize;
+ unsigned int frameSize;
+ unsigned int channels;
+ AEDataFormat format;
+ };
+
static snd_pcm_format_t AEFormatToALSAFormat(const enum AEDataFormat format);
- bool InitializeHW(AEAudioFormat &format);
- bool InitializeSW(AEAudioFormat &format);
+ bool InitializeHW(const ALSAConfig &inconfig, ALSAConfig &outconfig);
+ bool InitializeSW(const ALSAConfig &inconfig);
static void AppendParams(std::string &device, const std::string &params);
static bool TryDevice(const std::string &name, snd_pcm_t **pcmp, snd_config_t *lconf);
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp
index 2e774b478c..6619e5fb59 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp
@@ -1017,9 +1017,18 @@ bool CAESinkWASAPI::InitializeExclusive(AEAudioFormat &format)
{
WAVEFORMATEXTENSIBLE_IEC61937 wfxex_iec61937;
WAVEFORMATEXTENSIBLE &wfxex = wfxex_iec61937.FormatExt;
+ bool obsolete71Wide = false;
if (format.m_dataFormat <= AE_FMT_FLOAT)
+ {
BuildWaveFormatExtensible(format, wfxex);
+ // handle obsolete 7.1 wide
+ if (wfxex.dwChannelMask == KSAUDIO_SPEAKER_7POINT1)
+ {
+ obsolete71Wide = true;
+ wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
+ }
+ }
else
BuildWaveFormatExtensibleIEC61397(format, wfxex_iec61937);
@@ -1060,51 +1069,72 @@ bool CAESinkWASAPI::InitializeExclusive(AEAudioFormat &format)
CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s) - trying to find a compatible format", WASAPIErrToStr(hr));
int closestMatch;
+ unsigned int requestedChannels = wfxex.Format.nChannels;
+ unsigned int noOfCh;
/* The requested format is not supported by the device. Find something that works */
- for (int j = 0; j < sizeof(testFormats)/sizeof(sampleFormat); j++)
+ for (int layout = -1; layout <= (int)ARRAYSIZE(layoutsList); layout++)
{
- closestMatch = -1;
-
- wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
- wfxex.SubFormat = testFormats[j].subFormat;
- wfxex.Format.wBitsPerSample = testFormats[j].bitsPerSample;
- wfxex.Samples.wValidBitsPerSample = testFormats[j].validBitsPerSample;
- wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
+ // if requested layout is not suppported, try standard layouts with at least
+ // the number of channels as requested
+ // as the last resort try stereo
+ if (layout == ARRAYSIZE(layoutsList))
+ {
+ wfxex.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
+ wfxex.Format.nChannels = 2;
+ }
+ else if (layout >= 0)
+ {
+ wfxex.dwChannelMask = ChLayoutToChMask(layoutsList[layout], &noOfCh);
+ wfxex.Format.nChannels = noOfCh;
+ if (noOfCh < requestedChannels)
+ continue;
+ }
- for (int i = 0 ; i < WASAPISampleRateCount; i++)
+ for (int j = 0; j < sizeof(testFormats)/sizeof(sampleFormat); j++)
{
- wfxex.Format.nSamplesPerSec = WASAPISampleRates[i];
- wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
-
- /* Trace format match iteration loop via log */
- #if 0
- CLog::Log(LOGDEBUG, "WASAPI: Trying Format: %s, %d, %d, %d", CAEUtil::DataFormatToStr(testFormats[j].subFormatType),
- wfxex.Format.nSamplesPerSec,
- wfxex.Format.wBitsPerSample,
- wfxex.Samples.wValidBitsPerSample);
- #endif
+ closestMatch = -1;
- hr = m_pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
+ wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ wfxex.SubFormat = testFormats[j].subFormat;
+ wfxex.Format.wBitsPerSample = testFormats[j].bitsPerSample;
+ wfxex.Samples.wValidBitsPerSample = testFormats[j].validBitsPerSample;
+ wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
- if (SUCCEEDED(hr))
+ for (int i = 0 ; i < WASAPISampleRateCount; i++)
{
- /* If the current sample rate matches the source then stop looking and use it */
- if ((WASAPISampleRates[i] == format.m_sampleRate) && (testFormats[j].subFormatType <= format.m_dataFormat))
- goto initialize;
- /* If this rate is closer to the source then the previous one, save it */
- else if (closestMatch < 0 || abs((int)WASAPISampleRates[i] - (int)format.m_sampleRate) < abs((int)WASAPISampleRates[closestMatch] - (int)format.m_sampleRate))
- closestMatch = i;
- }
- else if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT)
+ wfxex.Format.nSamplesPerSec = WASAPISampleRates[i];
+ wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
+
+ /* Trace format match iteration loop via log */
+#if 0
+ CLog::Log(LOGDEBUG, "WASAPI: Trying Format: %s, %d, %d, %d", CAEUtil::DataFormatToStr(testFormats[j].subFormatType),
+ wfxex.Format.nSamplesPerSec,
+ wfxex.Format.wBitsPerSample,
+ wfxex.Samples.wValidBitsPerSample);
+#endif
+
+ hr = m_pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
+
+ if (SUCCEEDED(hr))
+ {
+ /* If the current sample rate matches the source then stop looking and use it */
+ if ((WASAPISampleRates[i] == format.m_sampleRate) && (testFormats[j].subFormatType <= format.m_dataFormat))
+ goto initialize;
+ /* If this rate is closer to the source then the previous one, save it */
+ else if (closestMatch < 0 || abs((int)WASAPISampleRates[i] - (int)format.m_sampleRate) < abs((int)WASAPISampleRates[closestMatch] - (int)format.m_sampleRate))
+ closestMatch = i;
+ }
+ else if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT)
CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s)", WASAPIErrToStr(hr));
- }
+ }
- if (closestMatch >= 0)
- {
- wfxex.Format.nSamplesPerSec = WASAPISampleRates[closestMatch];
- wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
- goto initialize;
+ if (closestMatch >= 0)
+ {
+ wfxex.Format.nSamplesPerSec = WASAPISampleRates[closestMatch];
+ wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
+ goto initialize;
+ }
}
}
@@ -1116,7 +1146,22 @@ bool CAESinkWASAPI::InitializeExclusive(AEAudioFormat &format)
initialize:
- AEChannelsFromSpeakerMask(wfxex.dwChannelMask);
+ // check if 7.1 wide was requested and we were able to open 8 channels
+ if (obsolete71Wide && (wfxex.dwChannelMask == KSAUDIO_SPEAKER_7POINT1_SURROUND))
+ {
+ // build layout for 7.1 Wide and map it into KSAUDIO_SPEAKER_7POINT1_SURROUND
+ m_channelLayout.Reset();
+ m_channelLayout += AE_CH_FLOC; // FLOC/FROC go into FL/FR
+ m_channelLayout += AE_CH_FROC;
+ m_channelLayout += AE_CH_FC;
+ m_channelLayout += AE_CH_LFE;
+ m_channelLayout += AE_CH_FL; // FL/FR go into SL/SR
+ m_channelLayout += AE_CH_FR;
+ m_channelLayout += AE_CH_BL;
+ m_channelLayout += AE_CH_BR;
+ }
+ else
+ AEChannelsFromSpeakerMask(wfxex.dwChannelMask);
format.m_channelLayout = m_channelLayout;
/* When the stream is raw, the values in the format structure are set to the link */
diff --git a/xbmc/cores/AudioEngine/Utils/AEChannelInfo.cpp b/xbmc/cores/AudioEngine/Utils/AEChannelInfo.cpp
index 69b37b470b..5d4857114b 100644
--- a/xbmc/cores/AudioEngine/Utils/AEChannelInfo.cpp
+++ b/xbmc/cores/AudioEngine/Utils/AEChannelInfo.cpp
@@ -55,11 +55,13 @@ void CAEChannelInfo::ResolveChannels(const CAEChannelInfo& rhs)
bool srcHasSR = false;
bool srcHasRL = false;
bool srcHasRR = false;
+ bool srcHasBC = false;
bool dstHasSL = false;
bool dstHasSR = false;
bool dstHasRL = false;
bool dstHasRR = false;
+ bool dstHasBC = false;
for (unsigned int c = 0; c < rhs.m_channelCount; ++c)
switch(rhs.m_channels[c])
@@ -68,6 +70,7 @@ void CAEChannelInfo::ResolveChannels(const CAEChannelInfo& rhs)
case AE_CH_SR: dstHasSR = true; break;
case AE_CH_BL: dstHasRL = true; break;
case AE_CH_BR: dstHasRR = true; break;
+ case AE_CH_BC: dstHasBC = true; break;
default:
break;
}
@@ -81,6 +84,7 @@ void CAEChannelInfo::ResolveChannels(const CAEChannelInfo& rhs)
case AE_CH_SR: srcHasSR = true; break;
case AE_CH_BL: srcHasRL = true; break;
case AE_CH_BR: srcHasRR = true; break;
+ case AE_CH_BC: srcHasBC = true; break;
default:
break;
}
@@ -97,6 +101,10 @@ void CAEChannelInfo::ResolveChannels(const CAEChannelInfo& rhs)
newInfo += m_channels[i];
}
+ // we let the sink do the mapping later on
+ if (m_channelCount == 8 && m_channelCount == rhs.Count())
+ return;
+
/* we need to ensure we end up with rear or side channels for downmix to work */
if (srcHasSL && !dstHasSL && dstHasRL)
newInfo += AE_CH_BL;
@@ -107,6 +115,21 @@ void CAEChannelInfo::ResolveChannels(const CAEChannelInfo& rhs)
if (srcHasRR && !dstHasRR && dstHasSR)
newInfo += AE_CH_SR;
+ // mix back center if not available in destination layout
+ // prefer mixing into backs if available
+ if (srcHasBC && !dstHasBC)
+ {
+ if (dstHasRL && !newInfo.HasChannel(AE_CH_BL))
+ newInfo += AE_CH_BL;
+ else if (dstHasSL && !newInfo.HasChannel(AE_CH_SL))
+ newInfo += AE_CH_SL;
+
+ if (dstHasRR && !newInfo.HasChannel(AE_CH_BR))
+ newInfo += AE_CH_BR;
+ else if (dstHasSR && !newInfo.HasChannel(AE_CH_SR))
+ newInfo += AE_CH_SR;
+ }
+
*this = newInfo;
}