Skip to content

Commit

Permalink
Merge temp/newaudiosettings branch.
Browse files Browse the repository at this point in the history
In short:
- Add new configuration screen, with testing screen
- No need to press Scan Audio Device anymore
- DTS-HD MA, E-AC3 and TrueHD passthrough
  • Loading branch information
jyavenard committed Dec 14, 2010
2 parents 7504555 + aa7298c commit b2a86a2
Show file tree
Hide file tree
Showing 37 changed files with 2,148 additions and 1,265 deletions.
4 changes: 2 additions & 2 deletions mythtv/libs/libmyth/audio/audiooutput.cpp
Expand Up @@ -48,11 +48,11 @@ AudioOutput *AudioOutput::OpenAudio(
const QString &main_device, const QString &passthru_device,
AudioFormat format, int channels, int codec, int samplerate,
AudioOutputSource source, bool set_initial_vol, bool passthru,
int upmixer_startup)
int upmixer_startup, AudioOutputSettings *custom)
{
AudioSettings settings(
main_device, passthru_device, format, channels, codec, samplerate,
source, set_initial_vol, passthru, upmixer_startup);
source, set_initial_vol, passthru, upmixer_startup, custom);

return OpenAudio(settings);
}
Expand Down
5 changes: 4 additions & 1 deletion mythtv/libs/libmyth/audio/audiooutput.h
Expand Up @@ -41,7 +41,7 @@ class MPUBLIC AudioOutput : public VolumeBase, public OutputListeners
const QString &audiodevice, const QString &passthrudevice,
AudioFormat format, int channels, int codec, int samplerate,
AudioOutputSource source, bool set_initial_vol, bool passthru,
int upmixer_startup = 0);
int upmixer_startup = 0, AudioOutputSettings *custom = NULL);
static AudioOutput *OpenAudio(AudioSettings &settings,
bool willsuspendpa = true);
static AudioOutput *OpenAudio(
Expand All @@ -60,6 +60,9 @@ class MPUBLIC AudioOutput : public VolumeBase, public OutputListeners

virtual void SetStretchFactor(float factor);
virtual float GetStretchFactor(void) const { return 1.0f; }
virtual int GetChannels(void) const { return 2; }
virtual AudioFormat GetFormat(void) const { return FORMAT_S16; };
virtual int GetBytesPerFrame(void) const { return 4; };

virtual AudioOutputSettings* GetOutputSettingsCleaned(void)
{ return new AudioOutputSettings; }
Expand Down
45 changes: 20 additions & 25 deletions mythtv/libs/libmyth/audio/audiooutputalsa.cpp
Expand Up @@ -55,7 +55,7 @@ AudioOutputALSA::AudioOutputALSA(const AudioSettings &settings) :
if (args < 0)
{
/* no existing parameters: add it behind device name */
passthru_device += ":AES0=6";
passthru_device += ":AES0=6,AES1=0x82,AES2=0x00,AES3=0x01";
}
else
{
Expand All @@ -66,12 +66,12 @@ AudioOutputALSA::AudioOutputALSA(const AudioSettings &settings) :
if (args == passthru_device.length())
{
/* ":" but no parameters */
passthru_device += "AES0=6";
passthru_device += "AES0=6,AES1=0x82,AES2=0x00,AES3=0x01";
}
else if (passthru_device[args] != '{')
{
/* a simple list of parameters: add it at the end of the list */
passthru_device += ",AES0=6";
passthru_device += ",AES0=6,AES1=0x82,AES2=0x00,AES3=0x01";
}
else
{
Expand All @@ -80,7 +80,8 @@ AudioOutputALSA::AudioOutputALSA(const AudioSettings &settings) :
--len;
while (len > 0 && passthru_device[len].isSpace());
if (passthru_device[len] == '}')
passthru_device = passthru_device.insert(len, " AES0=6");
passthru_device = passthru_device.insert(
len, " AES0=6 AES1 0x82 AES2=0x00 AES3=0x01");
}
}
}
Expand All @@ -106,6 +107,7 @@ int AudioOutputALSA::TryOpenDevice(int open_mode, int try_ac3)
if (try_ac3)
{
dev_ba = passthru_device.toAscii();
VBAUDIO(QString("OpenDevice %1 for passthrough").arg(passthru_device));
err = snd_pcm_open(&pcm_handle, dev_ba.constData(),
SND_PCM_STREAM_PLAYBACK, open_mode);
m_lastdevice = passthru_device;
Expand All @@ -120,6 +122,7 @@ int AudioOutputALSA::TryOpenDevice(int open_mode, int try_ac3)
if (!try_ac3 || err < 0)
{
// passthru open failed, retry default device
VBAUDIO(QString("OpenDevice %1").arg(main_device));
dev_ba = main_device.toAscii();
err = snd_pcm_open(&pcm_handle, dev_ba.constData(),
SND_PCM_STREAM_PLAYBACK, open_mode);
Expand Down Expand Up @@ -243,7 +246,8 @@ bool AudioOutputALSA::IncPreallocBufferSize(int buffer_time)
(buffer_time / 1000) *
output_bytes_per_frame / 1024;

VBAUDIO(QString("Prealloc buffer cur: %1 max: %3").arg(cur).arg(max));
VBAUDIO(QString("Prealloc buffer cur: %1 need: %2 max: %3")
.arg(cur).arg(size).arg(max));

if (size > max)
{
Expand Down Expand Up @@ -406,7 +410,7 @@ bool AudioOutputALSA::OpenDevice()
}

period_time = 50000; // aim for an interrupt every 50ms
buffer_time = period_time << 2; // buffer 200ms worth of samples
buffer_time = period_time << 3; // buffer 400ms worth of samples

err = SetParameters(pcm_handle, format, channels, samplerate,
buffer_time, period_time);
Expand Down Expand Up @@ -488,7 +492,10 @@ void AudioOutputALSA::WriteAudio(uchar *aubuf, int size)
return;
}

if ((!passthru && channels == 6) || channels == 8)
/* Audio received is using SMPTE channel ordering
* ALSA uses its own channel order.
* Do not re-order passthu audio */
if (!passthru && (channels == 6 || channels == 8))
ReorderSmpteToAlsa(aubuf, frames, output_format, channels - 6);

VERBOSE(VB_AUDIO+VB_TIMESTAMP,
Expand All @@ -497,7 +504,7 @@ void AudioOutputALSA::WriteAudio(uchar *aubuf, int size)

while (frames > 0)
{
lw = pcm_write_func(pcm_handle, tmpbuf, frames);
lw = snd_pcm_writei(pcm_handle, tmpbuf, frames);

if (lw >= 0)
{
Expand All @@ -517,7 +524,7 @@ void AudioOutputALSA::WriteAudio(uchar *aubuf, int size)
case -EPIPE:
if (snd_pcm_state(pcm_handle) == SND_PCM_STATE_XRUN)
{
VBERROR("WriteAudio: buffer underrun");
VBAUDIO("WriteAudio: buffer underrun");
if ((err = snd_pcm_prepare(pcm_handle)) < 0)
{
AERROR("WriteAudio: unable to recover from xrun");
Expand Down Expand Up @@ -604,22 +611,10 @@ int AudioOutputALSA::SetParameters(snd_pcm_t *handle, snd_pcm_format_t format,
err = snd_pcm_hw_params_any(handle, params);
CHECKERR("No playback configurations available");

/* set the interleaved read/write format, use mmap if available */
pcm_write_func = &snd_pcm_mmap_writei;
if ((err = snd_pcm_hw_params_set_access(handle, params,
SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0)
{
Warn("mmap not available, attempting to fall back to slow writes");
QString old_err = snd_strerror(err);
pcm_write_func = &snd_pcm_writei;
if ((err = snd_pcm_hw_params_set_access(handle, params,
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
Error("Interleaved sound types MMAP & RW are not available");
AERROR(QString("MMAP Error: %1\n\t\t\tRW Error").arg(old_err));
return err;
}
}
/* set the interleaved read/write format */
err = snd_pcm_hw_params_set_access(handle, params,
SND_PCM_ACCESS_RW_INTERLEAVED);
CHECKERR(QString("Interleaved RW audio not available"));

/* set the sample format */
err = snd_pcm_hw_params_set_format(handle, params, format);
Expand Down
2 changes: 0 additions & 2 deletions mythtv/libs/libmyth/audio/audiooutputalsa.h
Expand Up @@ -46,8 +46,6 @@ class AudioOutputALSA : public AudioOutputBase
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;

Expand Down
110 changes: 88 additions & 22 deletions mythtv/libs/libmyth/audio/audiooutputbase.cpp
Expand Up @@ -73,7 +73,7 @@ AudioOutputBase::AudioOutputBase(const AudioSettings &settings) :
pSoundStretch(NULL),
encoder(NULL), upmixer(NULL),
source_channels(-1), source_samplerate(0),
source_bytes_per_frame(0),
source_bytes_per_frame(0), upmix_default(false),
needs_upmix(false), needs_downmix(false),
surround_mode(QUALITY_LOW), old_stretchfactor(1.0f),
volume(80), volumeControl(QString()),
Expand Down Expand Up @@ -107,8 +107,7 @@ AudioOutputBase::AudioOutputBase(const AudioSettings &settings) :
src_quality = QUALITY_MEDIUM;

// Handle override of SRC quality settings
if (gCoreContext->GetNumSetting("AdvancedAudioSettings", false) &&
gCoreContext->GetNumSetting("SRCQualityOverride", false))
if (gCoreContext->GetNumSetting("SRCQualityOverride", false))
{
src_quality = gCoreContext->GetNumSetting("SRCQuality", QUALITY_MEDIUM);
// Extra test to keep backward compatibility with earlier SRC setting
Expand Down Expand Up @@ -145,6 +144,17 @@ AudioOutputBase::~AudioOutputBase()

void AudioOutputBase::InitSettings(const AudioSettings &settings)
{
if (settings.custom)
{
// got a custom audio report already, use it
// this was likely provided by the AudioTest utility
output_settings = new AudioOutputSettings;
*output_settings = *settings.custom;
max_channels = output_settings->BestSupportedChannels();
configured_channels = max_channels;
return;
}

// Ask the subclass what we can send to the device
output_settings = GetOutputSettingsUsers();

Expand All @@ -163,7 +173,7 @@ void AudioOutputBase::InitSettings(const AudioSettings &settings)
/**
* Returns capabilities supported by the audio device
* amended to take into account the digital audio
* options (AC3 and DTS)
* options (AC3, DTS, E-AC3 and TrueHD)
*/
AudioOutputSettings* AudioOutputBase::GetOutputSettingsCleaned(void)
{
Expand All @@ -185,7 +195,7 @@ AudioOutputSettings* AudioOutputBase::GetOutputSettingsCleaned(void)
/**
* Returns capabilities supported by the audio device
* amended to take into account the digital audio
* options (AC3 and DTS) as well as the user settings
* options (AC3, DTS, E-AC3 and TrueHD) as well as the user settings
*/
AudioOutputSettings* AudioOutputBase::GetOutputSettingsUsers(void)
{
Expand All @@ -211,10 +221,12 @@ bool AudioOutputBase::CanPassthrough(int samplerate, int channels) const
// 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;
// Will passthrough if surround audio was defined. Amplifier will
// do the downmix if required
ret &= max_channels >= 6;
// Stereo content will always be decoded so it can later be upmixed
// unless audio is configured for stereoo
ret |= channels == 2 && max_channels == 2;

return ret;
}
Expand Down Expand Up @@ -419,7 +431,8 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
VBAUDIO(QString("Original codec was %1, %2, %3 kHz, %4 channels")
.arg(ff_codec_id_string((CodecID)codec))
.arg(output_settings->FormatToString(format))
.arg(samplerate/1000).arg(source_channels));
.arg(samplerate/1000)
.arg(source_channels));

/* Encode to AC-3 if we're allowed to passthru but aren't currently
and we have more than 2 channels but multichannel PCM is not supported
Expand All @@ -429,22 +442,25 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
output_settings->canAC3() &&
((!output_settings->canLPCM() && configured_channels > 2) ||
!output_settings->IsSupportedChannels(channels)));
VBAUDIO(QString("enc(%1), passthru(%2), canAC3(%3), canDTS(%4), canLPCM(%5)"
", configured_channels(%6), %7 channels supported(%8)")
VBAUDIO(QString("enc(%1), passthru(%2), canAC3(%3), canDTS(%4), canHD(%5), "
"canHDLL(%6), canLPCM(%7), "
"configured_channels(%8), %9 channels supported(%10)")
.arg(enc)
.arg(passthru)
.arg(output_settings->canAC3())
.arg(output_settings->canDTS())
.arg(output_settings->canHD())
.arg(output_settings->canHDLL())
.arg(output_settings->canLPCM())
.arg(configured_channels)
.arg(channels).arg(output_settings->IsSupportedChannels(channels)));
.arg(channels)
.arg(output_settings->IsSupportedChannels(channels)));

int dest_rate = 0;

// Force resampling if we are encoding to AC3 and sr > 48k
// or if 48k override was checked in settings
if ((samplerate != 48000 &&
gCoreContext->GetNumSetting("AdvancedAudioSettings", false) &&
gCoreContext->GetNumSetting("Audio48kOverride", false)) ||
(enc && (samplerate > 48000 || (need_resampler && dest_rate > 48000))))
{
Expand Down Expand Up @@ -511,8 +527,46 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
}
}

source_bytes_per_frame = source_channels *
output_settings->SampleSize(format);
if (passthru)
{
switch (settings.codec)
{
case CODEC_ID_EAC3:
samplerate *= 4;
case CODEC_ID_AC3:
case CODEC_ID_DTS:
channels = 2;
break;
case CODEC_ID_TRUEHD:
channels = 8;
switch(samplerate)
{
case 48000:
case 96000:
case 192000:
samplerate = 192000;
break;
case 44100:
case 88200:
case 176400:
samplerate = 176400;
break;
default:
VBAUDIO("TrueHD: Unsupported samplerate");
break;
}
break;
}
//AC3, DTS, DTS-HD MA and TrueHD use 16 bits samples
format = output_format = FORMAT_S16;
source_bytes_per_frame = channels *
output_settings->SampleSize(format);
}
else
{
source_bytes_per_frame = source_channels *
output_settings->SampleSize(format);
}

// Turn on float conversion?
if (need_resampler || needs_upmix || needs_downmix ||
Expand All @@ -525,12 +579,20 @@ void AudioOutputBase::Reconfigure(const AudioSettings &orig_settings)
if (enc)
output_format = FORMAT_S16; // Output s16le for AC-3 encoder
else
output_format = output_settings->BestSupportedFormat();
{
// re-encode audio using same format as input if upmixing
// to minimize the memory sound buffer usage. There should be
// no siginificant quality loss
if (needs_upmix &&
output_settings->IsSupportedFormat(format))
{
output_format = format;
}
else
output_format = output_settings->BestSupportedFormat();
}
}

if (passthru)
channels = 2; // IEC958 bitstream - 2 ch

bytes_per_frame = processing ? 4 : output_settings->SampleSize(format);
bytes_per_frame *= channels;

Expand Down Expand Up @@ -967,6 +1029,7 @@ int AudioOutputBase::CopyWithUpmix(char *buffer, int frames, int &org_waud)
if (!needs_upmix)
{
int num = len;

if (bdiff <= num)
{
memcpy(WPOS, buffer, bdiff);
Expand Down Expand Up @@ -1045,7 +1108,8 @@ bool AudioOutputBase::AddFrames(void *in_buffer, int in_frames,
int org_waud = waud, afree = audiofree();
int frames = in_frames;
void *buffer = in_buffer;
int bpf = bytes_per_frame, len = frames * source_bytes_per_frame;
int bpf = bytes_per_frame;
int len = frames * source_bytes_per_frame;
int used = kAudioRingBufferSize - afree;
bool music = false;
int bdiff;
Expand Down Expand Up @@ -1110,7 +1174,8 @@ bool AudioOutputBase::AddFrames(void *in_buffer, int in_frames,

int frames_remaining = in_frames;
int frames_final = 0;
int maxframes = (kAudioSRCInputSize / source_channels) & ~0xf;
int maxframes = (kAudioSRCInputSize /
(passthru ? channels : source_channels)) & ~0xf;
int offset = 0;

while(frames_remaining > 0)
Expand All @@ -1131,6 +1196,7 @@ bool AudioOutputBase::AddFrames(void *in_buffer, int in_frames,
// Convert to floats
len = AudioOutputUtil::toFloat(format, src_in, buffer, len);
}

frames_remaining -= frames;

// Perform downmix if necessary
Expand Down

0 comments on commit b2a86a2

Please sign in to comment.