Skip to content

Commit

Permalink
[AE][SoftAE] Fixed segfaults & improved WAV handling
Browse files Browse the repository at this point in the history
Previously when a sound was played, if the format did not match the sink format
it would be re-loaded from the disk and re-sampled each time the sink re-opened.
This behaviour has been changed so that the samples are cached along with the
original format information. This will reduce the re-init latency.

A new method has been added to check if the current output WAV format is
compatible with the required output format, so that re-init is not performed
when it is not required. This fixes the soft suspend issue with SoftAE in
CSoftAE::MixSounds which caused stack smashing.

This also fixes a long standing bug in CSoftAE::MixSounds when multiple sounds
are played at once that was also causing stack smashing.
  • Loading branch information
Geoffrey McRae committed Sep 26, 2012
1 parent 360f41d commit 255052e
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 104 deletions.
51 changes: 30 additions & 21 deletions xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,30 +408,38 @@ void CSoftAE::InternalOpenSink()
m_chLayout = m_encoderFormat.m_channelLayout;
m_convertFn = CAEConvert::FrFloat(m_encoderFormat.m_dataFormat);
neededBufferSize = m_encoderFormat.m_frames * sizeof(float) * m_chLayout.Count();
CLog::Log(LOGDEBUG, "CSoftAE::Initialize - Encoding using layout: %s", ((std::string)m_chLayout).c_str());
CLog::Log(LOGDEBUG, "CSoftAE::InternalOpenSink - Encoding using layout: %s", ((std::string)m_chLayout).c_str());
}
else
{
m_convertFn = CAEConvert::FrFloat(m_sinkFormat.m_dataFormat);
neededBufferSize = m_sinkFormat.m_frames * sizeof(float) * m_chLayout.Count();
CLog::Log(LOGDEBUG, "CSoftAE::Initialize - Using speaker layout: %s", CAEUtil::GetStdChLayoutName(m_stdChLayout));
CLog::Log(LOGDEBUG, "CSoftAE::InternalOpenSink - Using speaker layout: %s", CAEUtil::GetStdChLayoutName(m_stdChLayout));
}

m_bytesPerSample = CAEUtil::DataFormatToBits(AE_FMT_FLOAT) >> 3;
m_frameSize = m_bytesPerSample * m_chLayout.Count();
}

CLog::Log(LOGDEBUG, "CSoftAE::InternalOpenSink - Internal Buffer Size: %d", neededBufferSize);
if (m_buffer.Size() < neededBufferSize)
m_buffer.Alloc(neededBufferSize);

if (reInit)
{
/* re-init sounds */
if (!m_rawPassthrough)
{
/* re-init incompatible sounds */
CSingleLock soundLock(m_soundLock);
for (SoundList::iterator itt = m_sounds.begin(); itt != m_sounds.end(); ++itt)
(*itt)->Initialize();
{
CSoftAESound *sound = *itt;
if (!sound->IsCompatible())
{
StopSound(sound);
sound->Initialize();
}
}
}

/* re-init streams */
Expand Down Expand Up @@ -618,7 +626,6 @@ void CSoftAE::Deinitialize()

delete m_encoder;
m_encoder = NULL;

ResetEncoder();
m_buffer.DeAlloc();

Expand Down Expand Up @@ -759,18 +766,21 @@ void CSoftAE::PlaySound(IAESound *sound)
if (m_soundMode == AE_SOUND_OFF || (m_soundMode == AE_SOUND_IDLE && m_streamsPlaying))
return;

float *samples = ((CSoftAESound*)sound)->GetSamples();
if (!samples)
return;

/* add the sound to the play list */
CSingleLock soundSampleLock(m_soundSampleLock);
SoundState ss = {
((CSoftAESound*)sound),
samples,
((CSoftAESound*)sound)->GetSampleCount()
};
m_playing_sounds.push_back(ss);
float *samples = ((CSoftAESound*)sound)->GetSamples();
if (!samples)
return;

/* add the sound to the play list */
CSingleLock soundSampleLock(m_soundSampleLock);
SoundState ss = {
((CSoftAESound*)sound),
samples,
((CSoftAESound*)sound)->GetSampleCount()
};
m_playing_sounds.push_back(ss);

/* wake to play the sound */
m_wake.Set();
}

void CSoftAE::FreeSound(IAESound *sound)
Expand Down Expand Up @@ -1013,12 +1023,12 @@ unsigned int CSoftAE::MixSounds(float *buffer, unsigned int samples)
return 0;

SoundStateList::iterator itt;

unsigned int mixed = 0;
CSingleLock lock(m_soundSampleLock);
for (itt = m_playing_sounds.begin(); itt != m_playing_sounds.end(); )
{
SoundState *ss = &(*itt);
float *out = buffer;

/* no more frames, so remove it from the list */
if (ss->sampleCount == 0)
Expand All @@ -1030,13 +1040,12 @@ unsigned int CSoftAE::MixSounds(float *buffer, unsigned int samples)

float volume = ss->owner->GetVolume();
unsigned int mixSamples = std::min(ss->sampleCount, samples);

#ifdef __SSE__
CAEUtil::SSEMulAddArray(buffer, ss->samples, volume, mixSamples);
CAEUtil::SSEMulAddArray(out, ss->samples, volume, mixSamples);
#else
float *sample_buffer = ss->samples;
for (unsigned int i = 0; i < mixSamples; ++i)
*buffer++ = *sample_buffer++ * volume;
*out++ = *sample_buffer++ * volume;
#endif

ss->sampleCount -= mixSamples;
Expand Down
21 changes: 15 additions & 6 deletions xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,26 +46,35 @@ CSoftAESound::CSoftAESound(const std::string &filename) :
m_volume (1.0f ),
m_inUse (0 )
{
m_wavLoader.Load(filename);
}

CSoftAESound::~CSoftAESound()
{
DeInitialize();
}

void CSoftAESound::DeInitialize()
{
m_wavLoader.DeInitialize();
}

bool CSoftAESound::Initialize()
bool CSoftAESound::IsCompatible()
{
DeInitialize();
if (!m_wavLoader.IsValid())
return false;

return m_wavLoader.IsCompatible(AE.GetSampleRate(), AE.GetChannelLayout());
}

if (!m_wavLoader.Initialize(m_filename, AE.GetSampleRate()))
bool CSoftAESound::Initialize()
{
if (!m_wavLoader.IsValid())
return false;

return m_wavLoader.Remap(AE.GetChannelLayout(), AE.GetStdChLayout());
return m_wavLoader.Initialize(
AE.GetSampleRate (),
AE.GetChannelLayout(),
AE.GetStdChLayout ()
);
}

unsigned int CSoftAESound::GetSampleCount()
Expand Down
3 changes: 2 additions & 1 deletion xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@ class CSoftAESound : public IAESound
virtual void SetVolume(float volume) { m_volume = std::max(0.0f, std::min(1.0f, volume)); }
virtual float GetVolume() { return m_volume ; }

bool IsCompatible();
unsigned int GetSampleCount();

/* ReleaseSamples must be called for each time GetSamples has been called */
virtual float* GetSamples ();
void ReleaseSamples();
private:
CCriticalSection m_critSection;
std::string m_filename;
std::string m_filename;
CAEWAVLoader m_wavLoader;
float m_volume;
int m_inUse;
Expand Down
Loading

0 comments on commit 255052e

Please sign in to comment.