Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Dirty audio #1138

Merged
merged 3 commits into from

1 participant

@theuni
Owner

This work comes from @jmarshallnz, I'm just the PR monkey.

  1. Don't have AE constantly converting and otherwise wasting resources when there is no sound output. Saves a boatload of cpu usage on embedded platforms.
  2. Pass the status from 1 down to the sinks, so that they can choose to be smarter when there's nothing to do.

Note that for 2, we don't actually change any sink behaviors, only give them the knowledge of whether the buffer contains silence or real audio. Some sinks may be able to do nothing, while others may have to keep silence flowing. I'll leave that to the various platform devs.

Cory Fields and others added some commits
@theuni theuni merged commit c1cecb9 into xbmc:master
@tru tru referenced this pull request from a commit in RasPlex/plex-home-theatre
@tru tru Added warning dialog for when user will clear a modified PlayQueue
Fixes #1138
551150b
@tru tru referenced this pull request from a commit in RasPlex/plex-home-theatre
@tru tru Added warning dialog for when user will clear a modified PlayQueue
Fixes #1138
3874365
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 11, 2012
  1. [SoftAE] pass audio/silence down to the sink so it can decide if it w…

    Cory Fields authored
    …ants to output
  2. [SoftAE] change RunOutputStage to take in a boolean for audio (vs sil…

    Jonathan Marshall authored Cory Fields committed
    …ence) and to return the number of samples taken by the output stage
  3. [SoftAE] don't process silence when we don't have to.

    Jonathan Marshall authored Cory Fields committed
This page is out of date. Refresh to see the latest.
View
51 xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp
@@ -854,11 +854,13 @@ void CSoftAE::Run()
CSingleLock runningLock(m_runningLock);
CLog::Log(LOGINFO, "CSoftAE::Run - Thread Started");
+ bool hasAudio = false;
while (m_running)
{
bool restart = false;
- (this->*m_outputStageFn)();
+ if ((this->*m_outputStageFn)(hasAudio) > 0)
+ hasAudio = false; /* taken some audio - reset our silence flag */
/* if we have enough room in the buffer */
if (m_buffer.Free() >= m_frameSize)
@@ -869,7 +871,8 @@ void CSoftAE::Run()
/* run the stream stage */
CSoftAEStream *oldMaster = m_masterStream;
- (this->*m_streamStageFn)(m_chLayout.Count(), out, restart);
+ if ((this->*m_streamStageFn)(m_chLayout.Count(), out, restart) > 0)
+ hasAudio = true; /* have some audio */
/* if in audiophile mode and the master stream has changed, flag for restart */
if (m_audiophile && oldMaster != m_masterStream)
@@ -895,10 +898,11 @@ void CSoftAE::AllocateConvIfNeeded(size_t convertedSize)
}
}
-void CSoftAE::MixSounds(float *buffer, unsigned int samples)
+unsigned int CSoftAE::MixSounds(float *buffer, unsigned int samples)
{
SoundStateList::iterator itt;
+ unsigned int mixed = 0;
CSingleLock lock(m_soundSampleLock);
for (itt = m_playing_sounds.begin(); itt != m_playing_sounds.end(); )
{
@@ -926,18 +930,24 @@ void CSoftAE::MixSounds(float *buffer, unsigned int samples)
ss->samples += mixSamples;
++itt;
+ ++mixed;
}
+ return mixed;
}
-void CSoftAE::FinalizeSamples(float *buffer, unsigned int samples)
+bool CSoftAE::FinalizeSamples(float *buffer, unsigned int samples, bool hasAudio)
{
if (m_soundMode != AE_SOUND_OFF)
- MixSounds(buffer, samples);
+ hasAudio |= MixSounds(buffer, samples) > 0;
+
+ /* no need to process if we don't have audio (buffer is memset to 0) */
+ if (!hasAudio)
+ return false;
if (m_muted)
{
memset(buffer, 0, samples * sizeof(float));
- return;
+ return false;
}
/* deamplify */
@@ -973,21 +983,22 @@ void CSoftAE::FinalizeSamples(float *buffer, unsigned int samples)
/* if there were no samples outside of the range, dont clamp the buffer */
if (!clamp)
- return;
+ return true;
CLog::Log(LOGDEBUG, "CSoftAE::FinalizeSamples - Clamping buffer of %d samples", samples);
CAEUtil::ClampArray(buffer, samples);
+ return true;
}
-void CSoftAE::RunOutputStage()
+int CSoftAE::RunOutputStage(bool hasAudio)
{
const unsigned int needSamples = m_sinkFormat.m_frames * m_sinkFormat.m_channelLayout.Count();
const size_t needBytes = needSamples * sizeof(float);
if (m_buffer.Used() < needBytes)
- return;
+ return 0;
void *data = m_buffer.Raw(needBytes);
- FinalizeSamples((float*)data, needSamples);
+ hasAudio = FinalizeSamples((float*)data, needSamples, hasAudio);
int wroteFrames;
if (m_convertFn)
@@ -998,7 +1009,7 @@ void CSoftAE::RunOutputStage()
data = m_converted;
}
- wroteFrames = m_sink->AddPackets((uint8_t*)data, m_sinkFormat.m_frames);
+ wroteFrames = m_sink->AddPackets((uint8_t*)data, m_sinkFormat.m_frames, hasAudio);
/* Return value of INT_MAX signals error in sink - restart */
if (wroteFrames == INT_MAX)
@@ -1009,12 +1020,13 @@ void CSoftAE::RunOutputStage()
}
m_buffer.Shift(NULL, wroteFrames * m_sinkFormat.m_channelLayout.Count() * sizeof(float));
+ return wroteFrames;
}
-void CSoftAE::RunRawOutputStage()
+int CSoftAE::RunRawOutputStage(bool hasAudio)
{
if(m_buffer.Used() < m_sinkBlockSize)
- return;
+ return 0;
void *data = m_buffer.Raw(m_sinkBlockSize);
@@ -1035,7 +1047,7 @@ void CSoftAE::RunRawOutputStage()
data = m_converted;
}
- int wroteFrames = m_sink->AddPackets((uint8_t *)data, m_sinkFormat.m_frames);
+ int wroteFrames = m_sink->AddPackets((uint8_t *)data, m_sinkFormat.m_frames, hasAudio);
/* Return value of INT_MAX signals error in sink - restart */
if (wroteFrames == INT_MAX)
@@ -1046,17 +1058,19 @@ void CSoftAE::RunRawOutputStage()
}
m_buffer.Shift(NULL, wroteFrames * m_sinkFormat.m_frameSize);
+ return wroteFrames;
}
-void CSoftAE::RunTranscodeStage()
+int CSoftAE::RunTranscodeStage(bool hasAudio)
{
/* if we dont have enough samples to encode yet, return */
unsigned int block = m_encoderFormat.m_frames * m_encoderFormat.m_frameSize;
unsigned int sinkBlock = m_sinkFormat.m_frames * m_sinkFormat.m_frameSize;
+ int encodedFrames = 0;
if (m_buffer.Used() >= block && m_encodedBuffer.Used() < sinkBlock * 2)
{
- FinalizeSamples((float*)m_buffer.Raw(block), m_encoderFormat.m_frameSamples);
+ hasAudio = FinalizeSamples((float*)m_buffer.Raw(block), m_encoderFormat.m_frameSamples, hasAudio);
void *buffer;
if (m_convertFn)
@@ -1078,7 +1092,7 @@ void CSoftAE::RunTranscodeStage()
else
buffer = m_buffer.Raw(block);
- int encodedFrames = m_encoder->Encode((float*)buffer, m_encoderFormat.m_frames);
+ encodedFrames = m_encoder->Encode((float*)buffer, m_encoderFormat.m_frames);
m_buffer.Shift(NULL, encodedFrames * m_encoderFormat.m_frameSize);
uint8_t *packet;
@@ -1094,7 +1108,7 @@ void CSoftAE::RunTranscodeStage()
/* if we have enough data to write */
if (m_encodedBuffer.Used() >= sinkBlock)
{
- int wroteFrames = m_sink->AddPackets((uint8_t*)m_encodedBuffer.Raw(sinkBlock), m_sinkFormat.m_frames);
+ int wroteFrames = m_sink->AddPackets((uint8_t*)m_encodedBuffer.Raw(sinkBlock), m_sinkFormat.m_frames, hasAudio);
/* Return value of INT_MAX signals error in sink - restart */
if (wroteFrames == INT_MAX)
@@ -1106,6 +1120,7 @@ void CSoftAE::RunTranscodeStage()
m_encodedBuffer.Shift(NULL, wroteFrames * m_sinkFormat.m_frameSize);
}
+ return encodedFrames;
}
unsigned int CSoftAE::RunRawStreamStage(unsigned int channelCount, void *out, bool &restart)
View
32 xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.h
@@ -195,15 +195,35 @@ class CSoftAE : public IThreadedAE
void AllocateConvIfNeeded(size_t convertedSize);
/* thread run stages */
- void MixSounds (float *buffer, unsigned int samples);
- void FinalizeSamples (float *buffer, unsigned int samples);
+
+ /*! \brief Mix UI sounds into the current stream.
+ \param buffer the buffer to mix into.
+ \param samples the number of samples in the buffer.
+ \return the number of sounds mixed into the buffer.
+ */
+ unsigned int MixSounds (float *buffer, unsigned int samples);
+
+ /*! \brief Finalize samples ready for sending to the output device.
+ Mixes in any UI sounds, applies volume adjustment, and clamps to [-1,1].
+ \param buffer the audio data.
+ \param samples the number of samples in the buffer.
+ \param hasAudio whether we have audio from a stream (true) or silence (false)
+ \return true if we have audio to output, false if we have only silence.
+ */
+ bool FinalizeSamples (float *buffer, unsigned int samples, bool hasAudio);
CSoftAEStream *m_masterStream;
- void (CSoftAE::*m_outputStageFn)();
- void RunOutputStage ();
- void RunRawOutputStage();
- void RunTranscodeStage();
+ /*! \brief Run the output stage on the audio.
+ Prepares streamed data, mixes in any UI sounds, converts to a format suitable
+ for the sink, then outputs to the sink.
+ \param hasAudio whether or not we have audio (true) or silence (false).
+ \return the number of samples sent to the sink.
+ */
+ int (CSoftAE::*m_outputStageFn)(bool);
+ int RunOutputStage (bool hasAudio);
+ int RunRawOutputStage(bool hasAudio);
+ int RunTranscodeStage(bool hasAudio);
unsigned int (CSoftAE::*m_streamStageFn)(unsigned int channelCount, void *out, bool &restart);
unsigned int RunRawStreamStage (unsigned int channelCount, void *out, bool &restart);
View
2  xbmc/cores/AudioEngine/Interfaces/AESink.h
@@ -72,7 +72,7 @@ class IAESink
/*
Adds packets to be sent out, this routine MUST block or sleep.
*/
- virtual unsigned int AddPackets(uint8_t *data, unsigned int frames) = 0;
+ virtual unsigned int AddPackets(uint8_t *data, unsigned int frames, bool hasAudio) = 0;
/*
Drain the sink
View
2  xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
@@ -474,7 +474,7 @@ double CAESinkALSA::GetCacheTotal()
return (double)m_bufferSize * m_formatSampleRateMul;
}
-unsigned int CAESinkALSA::AddPackets(uint8_t *data, unsigned int frames)
+unsigned int CAESinkALSA::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio)
{
if (!m_pcm)
return 0;
View
2  xbmc/cores/AudioEngine/Sinks/AESinkALSA.h
@@ -48,7 +48,7 @@ class CAESinkALSA : public IAESink
virtual double GetDelay ();
virtual double GetCacheTime ();
virtual double GetCacheTotal ();
- virtual unsigned int AddPackets (uint8_t *data, unsigned int frames);
+ virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
virtual void Drain ();
static void EnumerateDevicesEx(AEDeviceInfoList &list);
View
2  xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.h
@@ -43,7 +43,7 @@ class CAESinkDirectSound : public IAESink
virtual double GetDelay ();
virtual double GetCacheTime ();
virtual double GetCacheTotal ();
- virtual unsigned int AddPackets (uint8_t *data, unsigned int frames);
+ virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
static void EnumerateDevicesEx (AEDeviceInfoList &deviceInfoList);
private:
void AEChannelsFromSpeakerMask(DWORD speakers);
View
2  xbmc/cores/AudioEngine/Sinks/AESinkNULL.cpp
@@ -81,7 +81,7 @@ double CAESinkNULL::GetDelay()
return std::max(0.0, (double)(m_ts - CurrentHostCounter()) / 1000000.0f);
}
-unsigned int CAESinkNULL::AddPackets(uint8_t *data, unsigned int frames)
+unsigned int CAESinkNULL::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio)
{
float timeout = m_msPerFrame * frames;
m_ts = CurrentHostCounter() + MathUtils::round_int(timeout * 1000000.0f);
View
2  xbmc/cores/AudioEngine/Sinks/AESinkNULL.h
@@ -40,7 +40,7 @@ class CAESinkNULL : public IAESink
virtual double GetDelay ();
virtual double GetCacheTime () { return 0.0; }
virtual double GetCacheTotal () { return 0.0; }
- virtual unsigned int AddPackets (uint8_t *data, unsigned int frames);
+ virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
virtual void Drain ();
static void EnumerateDevices(AEDeviceList &devices, bool passthrough);
private:
View
2  xbmc/cores/AudioEngine/Sinks/AESinkOSS.cpp
@@ -427,7 +427,7 @@ double CAESinkOSS::GetDelay()
return (double)delay / (m_format.m_frameSize * m_format.m_sampleRate);
}
-unsigned int CAESinkOSS::AddPackets(uint8_t *data, unsigned int frames)
+unsigned int CAESinkOSS::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio)
{
int size = frames * m_format.m_frameSize;
int wrote = write(m_fd, data, size);
View
2  xbmc/cores/AudioEngine/Sinks/AESinkOSS.h
@@ -42,7 +42,7 @@ class CAESinkOSS : public IAESink
virtual double GetDelay ();
virtual double GetCacheTime () { return 0.0; } /* FIXME */
virtual double GetCacheTotal () { return 0.0; } /* FIXME */
- virtual unsigned int AddPackets (uint8_t *data, unsigned int frames);
+ virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
virtual void Drain ();
static void EnumerateDevicesEx(AEDeviceInfoList &list);
private:
View
2  xbmc/cores/AudioEngine/Sinks/AESinkProfiler.cpp
@@ -73,7 +73,7 @@ double CAESinkProfiler::GetDelay()
return 0.0f;
}
-unsigned int CAESinkProfiler::AddPackets(uint8_t *data, unsigned int frames)
+unsigned int CAESinkProfiler::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio)
{
int64_t ts = CurrentHostCounter();
CLog::Log(LOGDEBUG, "CAESinkProfiler::AddPackets - latency %f ms", (float)(ts - m_ts) / 1000000.0f);
View
2  xbmc/cores/AudioEngine/Sinks/AESinkProfiler.h
@@ -40,7 +40,7 @@ class CAESinkProfiler : public IAESink
virtual double GetDelay ();
virtual double GetCacheTime () { return 0.0; }
virtual double GetCacheTotal () { return 0.0; }
- virtual unsigned int AddPackets (uint8_t *data, unsigned int frames);
+ virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
virtual void Drain ();
static void EnumerateDevices(AEDeviceList &devices, bool passthrough);
private:
View
2  xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp
@@ -362,7 +362,7 @@ double CAESinkWASAPI::GetCacheTotal()
return hnsLatency / 10.0;
}
-unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames)
+unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio)
{
if (!m_initialized)
return 0;
View
2  xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h
@@ -43,7 +43,7 @@ class CAESinkWASAPI : public IAESink
virtual double GetDelay ();
virtual double GetCacheTime ();
virtual double GetCacheTotal ();
- virtual unsigned int AddPackets (uint8_t *data, unsigned int frames);
+ virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
static void EnumerateDevicesEx (AEDeviceInfoList &deviceInfoList);
private:
bool InitializeExclusive(AEAudioFormat &format);
Something went wrong with that request. Please try again.