Permalink
Browse files

Backport [27306-27307],[27317-27318],[27323],[27331-27333]. Improve d…

…igital passthrough auto-settings mainly a problem with some HDMI audio cards. Fix 5.1 upmixing of AC3 stereo content. Simplify LPCM configurations moving it to advanced settings, now it should under most circumstances be not necessary to bother with it.

This bump the API version which will require to recompile all plugins (make clean all)

git-svn-id: http://svn.mythtv.org/svn/branches/release-0-24-fixes@27334 7dbf422c-18fa-0310-86e9-fd20926502f2
  • Loading branch information...
1 parent d36d385 commit ba0e1ac2998fb742e12c040a1ffd7907169c1f34 @jyavenard jyavenard committed Nov 24, 2010
@@ -65,7 +65,7 @@ class MPUBLIC AudioOutput : public VolumeBase, public OutputListeners
{ return new AudioOutputSettings; }
virtual AudioOutputSettings* GetOutputSettingsUsers(void)
{ return new AudioOutputSettings; }
- virtual bool CanPassthrough(int samplerate) const = 0;
+ virtual bool CanPassthrough(int samplerate, int channels) const = 0;
// dsprate is in 100 * samples/second
virtual void SetEffDsp(int dsprate) = 0;
@@ -33,28 +33,60 @@ using namespace std;
AudioOutputALSA::AudioOutputALSA(const AudioSettings &settings) :
AudioOutputBase(settings),
pcm_handle(NULL),
- numbadioctls(0),
pbufsize(-1),
m_card(-1),
m_device(-1),
- m_subdevice(-1)
+ m_subdevice(-1),
+ m_autopassthrough(false)
{
m_mixer.handle = NULL;
m_mixer.elem = NULL;
// Set everything up
if (passthru_device == "auto")
{
+ m_autopassthrough = true;
passthru_device = main_device;
- if (!passthru_device.contains(":"))
- passthru_device += ":AES0=0x6,AES1=0x82,AES2=0x0,AES3=0x2";
+
+ /* to set the non-audio bit, use AES0=6 */
+ int len = passthru_device.length();
+ int args = passthru_device.indexOf(":");
+
+ if (args < 0)
+ {
+ /* no existing parameters: add it behind device name */
+ passthru_device += ":AES0=6";
+ }
else
{
- passthru_device = passthru_device.insert(
- passthru_device.indexOf(":") + 1,
- "AES0=0x6,AES1=0x82,AES2=0x0,AES3=0x2,");
+ do
+ ++args;
+ while (args < passthru_device.length() &&
+ passthru_device[args].isSpace());
+ if (args == passthru_device.length())
+ {
+ /* ":" but no parameters */
+ passthru_device += "AES0=6";
+ }
+ else if (passthru_device[args] != '{')
+ {
+ /* a simple list of parameters: add it at the end of the list */
+ passthru_device += ",AES0=6";
+ }
+ else
+ {
+ /* parameters in config syntax: add it inside the { } block */
+ do
+ --len;
+ while (len > 0 && passthru_device[len].isSpace());
+ if (passthru_device[len] == '}')
+ passthru_device = passthru_device.insert(len, " AES0=6");
+ }
}
}
+ else if (passthru_device.toLower() == "default")
+ passthru_device = main_device;
+
InitSettings(settings);
if (settings.init)
Reconfigure(settings);
@@ -67,6 +99,37 @@ AudioOutputALSA::~AudioOutputALSA()
KillAudio();
}
+int AudioOutputALSA::TryOpenDevice(int open_mode, int try_ac3)
+{
+ QString real_device;
+ QByteArray dev_ba;
+ int err = -1;
+
+ if (try_ac3)
+ {
+ dev_ba = passthru_device.toAscii();
+ err = snd_pcm_open(&pcm_handle, dev_ba.constData(),
+ SND_PCM_STREAM_PLAYBACK, open_mode);
+ m_lastdevice = passthru_device;
+ if (!m_autopassthrough)
+ return err;
+ if (err < 0)
+ {
+ VBAUDIO(QString("Auto setting passthrough failed (%1), defaulting "
+ "to main device").arg(snd_strerror(err)));
+ }
+ }
+ if (!try_ac3 || err < 0)
+ {
+ // passthru open failed, retry default device
+ dev_ba = main_device.toAscii();
+ err = snd_pcm_open(&pcm_handle, dev_ba.constData(),
+ SND_PCM_STREAM_PLAYBACK, open_mode);
+ m_lastdevice = main_device;
+ }
+ return err;
+}
+
int AudioOutputALSA::GetPCMInfo(int &card, int &device, int &subdevice)
{
// Check for saved values
@@ -204,20 +267,17 @@ AudioOutputSettings* AudioOutputALSA::GetOutputSettings()
int rate;
int err;
- QString real_device = (passthru || enc) ? passthru_device : main_device;
-
AudioOutputSettings *settings = new AudioOutputSettings();
if (pcm_handle)
{
snd_pcm_close(pcm_handle);
pcm_handle = NULL;
}
- QByteArray dev_ba = real_device.toAscii();
- if((err = snd_pcm_open(&pcm_handle, dev_ba.constData(),
- SND_PCM_STREAM_PLAYBACK, OPEN_FLAGS)) < 0)
+
+ if((err = TryOpenDevice(OPEN_FLAGS, passthru || enc)) < 0)
{
- AERROR(QString("snd_pcm_open(\"%1\")").arg(real_device));
+ AERROR(QString("snd_pcm_open(\"%1\")").arg(m_lastdevice));
delete settings;
return NULL;
}
@@ -227,11 +287,9 @@ AudioOutputSettings* AudioOutputALSA::GetOutputSettings()
if ((err = snd_pcm_hw_params_any(pcm_handle, params)) < 0)
{
snd_pcm_close(pcm_handle);
- if((err = snd_pcm_open(&pcm_handle, dev_ba.constData(),
- SND_PCM_STREAM_PLAYBACK, OPEN_FLAGS&FILTER_FLAGS
- )) < 0)
+ if((err = TryOpenDevice(OPEN_FLAGS&FILTER_FLAGS, passthru || enc)) < 0)
{
- AERROR(QString("snd_pcm_open(\"%1\")").arg(real_device));
+ AERROR(QString("snd_pcm_open(\"%1\")").arg(m_lastdevice));
delete settings;
return NULL;
}
@@ -277,6 +335,9 @@ AudioOutputSettings* AudioOutputALSA::GetOutputSettings()
QMap<QString, QString> *alsadevs = GetALSADevices("pcm");
while(1)
{
+ QString real_device = (((passthru || enc) && !m_autopassthrough) ?
+ passthru_device : main_device);
+
QString desc = alsadevs->value(real_device);
settings->setPassthrough(1); // yes passthrough
@@ -314,30 +375,13 @@ bool AudioOutputALSA::OpenDevice()
snd_pcm_format_t format;
uint buffer_time, period_time;
int err;
- QString real_device;
if (pcm_handle != NULL)
CloseDevice();
- numbadioctls = 0;
-
- if (passthru || enc)
- {
- real_device = passthru_device;
- }
- else
- {
- real_device = main_device;
- }
-
- VERBOSE(VB_GENERAL, QString("Opening ALSA audio device '%1'.")
- .arg(real_device));
-
- QByteArray dev_ba = real_device.toAscii();
- if ((err = snd_pcm_open(&pcm_handle, dev_ba.constData(),
- SND_PCM_STREAM_PLAYBACK, OPEN_FLAGS&FILTER_FLAGS)) < 0)
+ if ((err = TryOpenDevice(0, passthru || enc)) < 0)
{
- AERROR(QString("snd_pcm_open(%1)").arg(real_device));
+ AERROR(QString("snd_pcm_open(\"%1\")").arg(m_lastdevice));
if (pcm_handle)
CloseDevice();
return false;
@@ -31,6 +31,7 @@ class AudioOutputALSA : public AudioOutputBase
AudioOutputSettings* GetOutputSettings(void);
private:
+ int TryOpenDevice(int open_mode, int try_ac3);
int GetPCMInfo(int &card, int &device, int &subdevice);
bool SetPreallocBufferSize(int size);
bool IncPreallocBufferSize(int buffer_time);
@@ -42,12 +43,14 @@ class AudioOutputALSA : public AudioOutputBase
private:
snd_pcm_t *pcm_handle;
- int numbadioctls;
int pbufsize;
int m_card, m_device, m_subdevice;
QMutex killAudioLock;
snd_pcm_sframes_t (*pcm_write_func)(snd_pcm_t*, const void*,
snd_pcm_uframes_t);
+ bool m_autopassthrough;
+ QString m_lastdevice;
+
struct {
QString device;
QString control;
@@ -200,11 +200,18 @@ AudioOutputSettings* AudioOutputBase::GetOutputSettingsUsers(void)
/**
* Test if we can output digital audio and if sample rate is supported
*/
-bool AudioOutputBase::CanPassthrough(int samplerate) const
+bool AudioOutputBase::CanPassthrough(int samplerate, int channels) const
{
bool ret = false;
ret = output_settings->IsSupportedFormat(FORMAT_S16);
ret &= output_settings->IsSupportedRate(samplerate);
+ // Don't know any cards that support spdif clocked at < 44100
+ // Some US cable transmissions have 2ch 32k AC-3 streams
+ ret &= samplerate >= 44100;
+ // Will downmix if we can't support the amount of channels
+ ret &= channels <= max_channels;
+ // Stereo content will always be decoded so it can later be upmixed
+ ret &= channels != 2;
return ret;
}
@@ -62,7 +62,7 @@ class AudioOutputBase : public AudioOutput, public QThread
virtual void SetStretchFactor(float factor);
virtual float GetStretchFactor(void) const;
- virtual bool CanPassthrough(int samplerate) const;
+ virtual bool CanPassthrough(int samplerate, int channels) const;
virtual bool ToggleUpmix(void);
virtual void Reset(void);
@@ -108,7 +108,7 @@ AudioOutputDX::AudioOutputDX(const AudioSettings &settings) :
{
timeBeginPeriod(1);
InitSettings(settings);
- if (passthru_device == "auto")
+ if (passthru_device == "auto" || passthru_device.toLower() == "default")
passthru_device = main_device;
if (settings.init)
Reconfigure(settings);
@@ -299,16 +299,16 @@ AudioOutputSettings* AudioOutputSettings::GetUsers(bool newcopy)
int cur_channels = gCoreContext->GetNumSetting("MaxChannels", 2);
int max_channels = aosettings->BestSupportedChannels();
- bool bForceDigital = gCoreContext->GetNumSetting("AdvancedAudioSettings", false) &&
+ bool bAdv = gCoreContext->GetNumSetting("AdvancedAudioSettings", false);
+ bool bForceDigital = bAdv &&
gCoreContext->GetNumSetting("PassThruDeviceOverride", false);
-
bool bAC3 = (aosettings->m_AC3 || bForceDigital) &&
gCoreContext->GetNumSetting("AC3PassThru", false);
bool bDTS = (aosettings->m_DTS || bForceDigital) &&
gCoreContext->GetNumSetting("DTSPassThru", false);
bool bLPCM = aosettings->m_LPCM &&
(aosettings->m_passthrough == -1 ||
- gCoreContext->GetNumSetting("MultiChannelPCM", false));
+ (bAdv && !gCoreContext->GetNumSetting("StereoPCM", false)));
if (max_channels > 2 && !bLPCM)
max_channels = 2;
@@ -319,8 +319,6 @@ AudioOutputSettings* AudioOutputSettings::GetUsers(bool newcopy)
cur_channels = max_channels;
aosettings->SetBestSupportedChannels(cur_channels);
- if (cur_channels <= 2)
- bDTS = bAC3 = false;
aosettings->m_AC3 = bAC3;
aosettings->m_DTS = bDTS;
aosettings->m_LPCM = bLPCM;
@@ -103,14 +103,14 @@ AudioSettings::AudioSettings(
void AudioSettings::FixPassThrough(void)
{
- if (passthru_device.isEmpty() || passthru_device.toLower() == "default")
+ if (passthru_device.isEmpty())
passthru_device = "auto";
}
void AudioSettings::TrimDeviceType(void)
{
main_device.remove(0, 5);
- if (passthru_device != "auto")
+ if (passthru_device != "auto" && passthru_device.toLower() != "default")
passthru_device.remove(0, 5);
}
@@ -11,7 +11,7 @@
/// Update this whenever the plug-in API changes.
/// Including changes in the libmythdb, libmyth, libmythtv, libmythav* and
/// libmythui class methods used by plug-ins.
-#define MYTH_BINARY_VERSION "0.24.20101028-1"
+#define MYTH_BINARY_VERSION "0.24.20101124-1"
/** \brief Increment this whenever the MythTV network protocol changes.
*
@@ -321,11 +321,11 @@ uint AudioPlayer::GetMaxChannels(void)
return ret;
}
-bool AudioPlayer::CanPassthrough(int samplerate)
+bool AudioPlayer::CanPassthrough(int samplerate, int channels)
{
bool ret = false;
if (m_audioOutput)
- ret = m_audioOutput->CanPassthrough(samplerate);
+ ret = m_audioOutput->CanPassthrough(samplerate, channels);
return ret;
}
@@ -39,7 +39,7 @@ class MPUBLIC AudioPlayer
float GetStretchFactor(void) { return m_stretchfactor; }
void SetStretchFactor(float factor);
bool ToggleUpmix(void);
- bool CanPassthrough(int samplerate);
+ bool CanPassthrough(int samplerate, int channels);
bool CanAC3(void);
bool CanDTS(void);
uint GetMaxChannels(void);
@@ -4603,14 +4603,9 @@ bool AvFormatDecoder::DoPassThrough(const AVCodecContext *ctx)
passthru = m_audio->CanAC3();
else if (ctx->codec_id == CODEC_ID_DTS)
passthru = m_audio->CanDTS();
- passthru &= m_audio->CanPassthrough(ctx->sample_rate);
- // Will downmix if we can't support the amount of channels
- passthru &= ctx->channels <= (int)m_audio->GetMaxChannels();
+ passthru &= m_audio->CanPassthrough(ctx->sample_rate, ctx->channels);
passthru &= !internal_vol;
passthru &= !transcoding && !disable_passthru;
- // Don't know any cards that support spdif clocked at < 44100
- // Some US cable transmissions have 2ch 32k AC-3 streams
- passthru &= ctx->sample_rate >= 44100;
return passthru;
}
Oops, something went wrong.

0 comments on commit ba0e1ac

Please sign in to comment.