Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Dirty audio #1138

Merged
merged 3 commits into from Jul 11, 2012
@@ -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)
@@ -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);
@@ -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
@@ -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;
@@ -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);
@@ -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);
@@ -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);
@@ -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:
@@ -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);
@@ -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:
@@ -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);
@@ -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:
@@ -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;
@@ -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);