Permalink
Browse files

Audio Framework: handle more configuration scenarios. Bug fixes

Bug fixes:
- If re-encoding to AC3 was occurring while downmixing: audio would be distorted
- Couldn't play 6.1 or 7.0 audio with LPCM/Analog out
- Wouldn't play DTS-HD High-Res unless HBRPassthrough was unchecked

New Features:
* We should now be able to play any number of channels combination from 1 to 8.
  - 1,3,4 will be downmixed to stereo
  - 2 and 5 will be upmixed to 5.1
  - 7,8 will be downmixed to 5.1 if supported, or stereo otherwise.
  This will only occur if the requested audio configuration isn't supported.
* Mono upmixing can be toggled between stereo or 5.1
  • Loading branch information...
1 parent e05e503 commit 4e5d52aac9e92ef796b8452aa27b8f41e0d9c5a8 @jyavenard jyavenard committed Oct 1, 2011
@@ -373,8 +373,8 @@ float AudioOutputBase::GetStretchFactor(void) const
*/
bool AudioOutputBase::ToggleUpmix(void)
{
- // Can only upmix from stereo to 6 ch
- if (max_channels == 2 || source_channels != 2 || passthru)
+ // Can only upmix from mono/stereo to 6 ch
+ if (max_channels == 2 || source_channels > 2 || passthru)
return false;
upmix_default = !upmix_default;
@@ -392,11 +392,17 @@ bool AudioOutputBase::ToggleUpmix(void)
bool AudioOutputBase::SetupPassthrough(int codec, int codec_profile,
int &samplerate_tmp, int &channels_tmp)
{
+ if (codec == CODEC_ID_DTS &&
+ !output_settingsdigital->canFeature(FEATURE_DTSHD))
+ {
+ // We do not support DTS-HD bitstream so force extraction of the
+ // DTS core track instead
+ codec_profile = FF_PROFILE_DTS;
+ }
QString log = AudioOutputSettings::GetPassthroughParams(
codec, codec_profile,
samplerate_tmp, channels_tmp,
output_settingsdigital->GetMaxHDRate() == 768000);
-
VBAUDIO("Setting " + log + " passthrough");
if (m_spdifenc)
@@ -415,12 +421,8 @@ bool AudioOutputBase::SetupPassthrough(int codec, int codec_profile,
m_spdifenc->SetMaxHDRate(0);
break;
case FF_PROFILE_DTS_HD_HRA:
- m_spdifenc->SetMaxHDRate(
- OutputSettings(true)->canFeature(FEATURE_DTSHD) ?
- 192000 : 0);
- break;
case FF_PROFILE_DTS_HD_MA:
- m_spdifenc->SetMaxHDRate(OutputSettings(true)->GetMaxHDRate());
+ m_spdifenc->SetMaxHDRate(samplerate_tmp * channels_tmp / 2);
break;
}
}
@@ -448,39 +450,59 @@ AudioOutputSettings *AudioOutputBase::OutputSettings(bool digital)
*/
void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
{
- AudioSettings settings = orig_settings;
- int lsource_channels = settings.channels;
- bool lneeds_upmix = false;
- bool lneeds_downmix = false;
- bool lreenc = false;
+ AudioSettings settings = orig_settings;
+ int lsource_channels = settings.channels;
+ int lconfigured_channels = configured_channels;
+ bool lneeds_upmix = false;
+ bool lneeds_downmix = false;
+ bool lreenc = false;
if (!settings.use_passthru)
{
// update channels configuration if source_channels has changed
if (lsource_channels > configured_channels)
{
if (lsource_channels <= 6)
- configured_channels = min(max_channels, 6);
+ lconfigured_channels = min(max_channels, 6);
else if (lsource_channels > 6)
- configured_channels = max_channels;
+ lconfigured_channels = max_channels;
}
else
{
- // if source was mono or 5.0, and hardware doesn't support it
- // we will upmix it respectively to stereo or 5.1
- // (can safely assume hardware supports stereo)
- // Ideally we should be able to upmix any channels configuration
- if ((lsource_channels == 1 || lsource_channels == 5) &&
- !output_settings->IsSupportedChannels(lsource_channels))
+ if (!output_settings->IsSupportedChannels(lsource_channels))
{
- // 1 => 2, 5 => 6
- configured_channels = lsource_channels + 1;
+ // if hardware doesn't support source audio configuration
+ // we will upmix/downmix to what we can
+ // (can safely assume hardware supports stereo)
+ switch (lsource_channels)
+ {
+ case 1:
+ lconfigured_channels = upmix_default ? 6 : 2;
+ break;
+ case 2:
+ //Will never happen
+ case 3:
+ case 4:
+ case 6:
+ lconfigured_channels = 2;
+ break;
+ case 5:
+ case 7:
+ if (output_settings->IsSupportedChannels(6))
+ lconfigured_channels = 6;
+ else
+ lconfigured_channels = 2;
+ break;
+ default:
+ lconfigured_channels = max_channels;
+ break;
+ }
}
else
- configured_channels = (upmix_default && lsource_channels == 2) ?
+ lconfigured_channels =
+ (upmix_default && lsource_channels <= 2) ?
max_channels : lsource_channels;
}
-
/* Might we reencode a bitstream that's been decoded for timestretch?
If the device doesn't support the number of channels - see below */
if (output_settingsdigital->canFeature(FEATURE_AC3) &&
@@ -490,20 +512,21 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
}
// Enough channels? Upmix if not, but only from mono/stereo/5.0 to 5.1
- if (IS_VALID_UPMIX_CHANNEL(settings.channels) && settings.channels < configured_channels)
+ if (IS_VALID_UPMIX_CHANNEL(settings.channels) &&
+ settings.channels < lconfigured_channels)
{
- int conf_channels = (configured_channels > 6) ?
- 6 : configured_channels;
+ lconfigured_channels =
+ (lconfigured_channels > 6) ? 6 : lconfigured_channels;
VBAUDIO(QString("Needs upmix from %1 -> %2 channels")
- .arg(settings.channels).arg(conf_channels));
- settings.channels = conf_channels;
+ .arg(settings.channels).arg(lconfigured_channels));
+ settings.channels = lconfigured_channels;
lneeds_upmix = true;
}
- else if (settings.channels > max_channels)
+ else if (settings.channels > lconfigured_channels)
{
VBAUDIO(QString("Needs downmix from %1 -> %2 channels")
- .arg(settings.channels).arg(max_channels));
- settings.channels = max_channels;
+ .arg(settings.channels).arg(lconfigured_channels));
+ settings.channels = lconfigured_channels;
lneeds_downmix = true;
}
}
@@ -517,13 +540,6 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
int samplerate_tmp, channels_tmp;
if (settings.use_passthru)
{
- if (settings.codec == CODEC_ID_DTS &&
- !output_settingsdigital->canFeature(FEATURE_DTSHD))
- {
- // We do not support DTS-HD bitstream so force extraction of the
- // DTS core track instead
- settings.codec_profile = FF_PROFILE_DTS;
- }
samplerate_tmp = settings.samplerate;
SetupPassthrough(settings.codec, settings.codec_profile,
samplerate_tmp, channels_tmp);
@@ -535,6 +551,7 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
settings.format == format &&
settings.samplerate == source_samplerate &&
settings.use_passthru == passthru &&
+ lconfigured_channels == configured_channels &&
lneeds_upmix == needs_upmix && lreenc == reenc &&
lsource_channels == source_channels &&
lneeds_downmix == needs_downmix;
@@ -559,6 +576,7 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
reenc = lreenc;
codec = settings.codec;
passthru = settings.use_passthru;
+ configured_channels = lconfigured_channels;
needs_upmix = lneeds_upmix;
needs_downmix = lneeds_downmix;
format = output_format = settings.format;
@@ -593,13 +611,15 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
!output_settings->IsSupportedChannels(channels)));
VBAUDIO(QString("enc(%1), passthru(%2), features (%3) "
- "configured_channels(%4), %5 channels supported(%6)")
+ "configured_channels(%4), %5 channels supported(%6) "
+ "max_channels(%7)")
.arg(enc)
.arg(passthru)
.arg(output_settingsdigital->FeaturesToString())
.arg(configured_channels)
.arg(channels)
- .arg(output_settings->IsSupportedChannels(channels)));
+ .arg(output_settings->IsSupportedChannels(channels))
+ .arg(max_channels));
int dest_rate = 0;
@@ -630,7 +650,7 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
.arg(settings.samplerate/1000).arg(samplerate/1000)
.arg(quality_string(src_quality)));
- int chans = needs_downmix ? channels : source_channels;
+ int chans = needs_downmix ? configured_channels : source_channels;
src_ctx = src_new(2-src_quality, chans, &error);
if (error)
@@ -748,13 +768,12 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
volume = gCoreContext->GetNumSetting(volumeControl, 80);
}
- VolumeBase::SetChannels(channels);
+ VolumeBase::SetChannels(configured_channels);
VolumeBase::SyncVolume();
VolumeBase::UpdateVolume();
- // Upmix Stereo or 5.0 to 5.1
- if (needs_upmix &&
- (source_channels == 2 || source_channels == 5) &&
+ // Upmix Mono, Stereo or 5.0 to 5.1
+ if (needs_upmix && IS_VALID_UPMIX_CHANNEL(source_channels) &&
configured_channels > 2)
{
surround_mode = gCoreContext->GetNumSetting("AudioUpmixType", QUALITY_HIGH);
@@ -1162,7 +1181,7 @@ int AudioOutputBase::CopyWithUpmix(char *buffer, int frames, int &org_waud)
}
// Convert mono to stereo as most devices can't accept mono
- if (channels == 2 && source_channels == 1)
+ if (configured_channels == 2 && source_channels == 1)
{
int bdFrames = bdiff / bpf;
if (bdFrames <= frames)
@@ -1318,7 +1337,7 @@ bool AudioOutputBase::AddData(void *in_buffer, int in_len,
// Account for changes in number of channels
if (needs_upmix || needs_downmix)
- len = (len / source_channels) * channels;
+ len = (len / source_channels) * configured_channels;
// Check we have enough space to write the data
if (need_resampler && src_ctx)
@@ -1367,7 +1386,8 @@ bool AudioOutputBase::AddData(void *in_buffer, int in_len,
// Perform downmix if necessary
if (needs_downmix)
- if(AudioOutputDownmix::DownmixFrames(source_channels, channels,
+ if(AudioOutputDownmix::DownmixFrames(source_channels,
+ configured_channels,
src_in, src_in, frames) < 0)
VBERROR("Error occurred while downmixing");
@@ -1685,10 +1705,11 @@ int AudioOutputBase::GetAudioData(uchar *buffer, int size, bool full_buffer,
// Mute individual channels through mono->stereo duplication
MuteState mute_state = GetMuteState();
- if (written_size && channels > 1 &&
+ if (!enc && !passthru &&
+ written_size && configured_channels > 1 &&
(mute_state == kMuteLeft || mute_state == kMuteRight))
{
- AudioOutputUtil::MuteChannel(obytes << 3, channels,
+ AudioOutputUtil::MuteChannel(obytes << 3, configured_channels,
mute_state == kMuteLeft ? 0 : 1,
buffer, written_size);
}
@@ -1,7 +1,10 @@
+#include "audiooutputbase.h"
#include "audiooutputdownmix.h"
#include "string.h"
+#define LOC QString("Downmixer: ")
+
/*
SMPTE channel layout
DUAL-MONO L R
@@ -134,9 +137,11 @@ static const float s51_matrix[2][8][6] =
int AudioOutputDownmix::DownmixFrames(int channels_in, int channels_out,
float *dst, float *src, int frames)
{
- if (channels_in <= channels_out)
+ if (channels_in < channels_out)
return -1;
+ //VBAUDIO(LOC + QString("Downmixing %1 frames (in:%2 out:%3)")
+ // .arg(frames).arg(channels_in).arg(channels_out));
if (channels_out == 2)
{
float tmp;
@@ -155,21 +160,36 @@ int AudioOutputDownmix::DownmixFrames(int channels_in, int channels_out,
}
else if (channels_out == 6)
{
- int lensamples = channels_in - 4;
- int lenbytes = lensamples * sizeof(float);
- for (int n=0; n < frames; n++)
+ // dummy 5.1 -> 5.1 downmixer for test purposes
+ if (channels_in == 6)
+ {
+ int lensamples = channels_in;
+ int lenbytes = lensamples * sizeof(float);
+ for (int n=0; n < frames; n++)
+ {
+ memcpy(dst, src, lenbytes);
+ src += lensamples;
+ dst += lensamples;
+ }
+ }
+ else
{
- memcpy(dst, src, lenbytes);
- src += lensamples;
- dst += 4;
- //read value first, as src and dst can overlap
- float ls = src[0];
- float rs = src[1];
- float rls = src[2];
- float rrs = src[3];
- *dst++ = ls * m3db + rls * m3db; // LS = LS*-3dB + Rls*-3dB
- *dst++ = rs * m3db + rrs * m3db; // RS = RS*-3dB + Rrs*-3dB
- src += 4;
+ int lensamples = channels_in - 4;
+ int lenbytes = lensamples * sizeof(float);
+ for (int n=0; n < frames; n++)
+ {
+ memcpy(dst, src, lenbytes);
+ src += lensamples;
+ dst += 4;
+ //read value first, as src and dst can overlap
+ float ls = src[0];
+ float rs = src[1];
+ float rls = src[2];
+ float rrs = src[3];
+ *dst++ = ls * m3db + rls * m3db; // LS = LS*-3dB + Rls*-3dB
+ *dst++ = rs * m3db + rrs * m3db; // RS = RS*-3dB + Rrs*-3dB
+ src += 4;
+ }
}
}
else
@@ -450,6 +450,9 @@ QString AudioOutputSettings::GetPassthroughParams(int codec, int codec_profile,
log = "DTS 96/24";
break;
case FF_PROFILE_DTS_HD_HRA:
+ samplerate = 192000;
+ log = "DTS-HD High-Res";
+ break;
case FF_PROFILE_DTS_HD_MA:
samplerate = 192000;
if (canDTSHDMA)

0 comments on commit 4e5d52a

Please sign in to comment.