Skip to content

Commit

Permalink
Merge pull request #1548 from DDDamian/SoftSuspendSink
Browse files Browse the repository at this point in the history
[AE] Allow sink to decide how or if it can be suspended
  • Loading branch information
davilla committed Nov 30, 2012
2 parents cd5a8c3 + 2b41991 commit f528cd3
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 35 deletions.
78 changes: 50 additions & 28 deletions xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp
Expand Up @@ -1017,34 +1017,8 @@ void CSoftAE::Run()
restart = true;
}

if (m_playingStreams.empty() && m_playing_sounds.empty() && m_streams.empty() &&
!m_softSuspend && !g_advancedSettings.m_streamSilence)
{
m_softSuspend = true;
m_softSuspendTimer = XbmcThreads::SystemClockMillis() + 10000; //10.0 second delay for softSuspend
}

unsigned int curSystemClock = XbmcThreads::SystemClockMillis();

/* idle while in Suspend() state until Resume() called */
/* idle if nothing to play and user hasn't enabled */
/* continuous streaming (silent stream) in as.xml */
while ((m_isSuspended || (m_softSuspend && (curSystemClock > m_softSuspendTimer))) &&
m_running && !m_reOpen && !restart)
{
if (m_sink)
{
/* take the sink lock */
CExclusiveLock sinkLock(m_sinkLock);
//m_sink->Drain(); TODO: implement
m_sink->Deinitialize();
delete m_sink;
m_sink = NULL;
}
if (!m_playingStreams.empty() || !m_playing_sounds.empty() || !m_sounds.empty())
m_softSuspend = false;
m_wake.WaitMSec(SOFTAE_IDLE_WAIT_MSEC);
}
/* Handle idle or forced suspend */
ProcessSuspend();

/* if we are told to restart */
if (m_reOpen || restart || !m_sink)
Expand Down Expand Up @@ -1405,3 +1379,51 @@ inline void CSoftAE::RemoveStream(StreamList &streams, CSoftAEStream *stream)
m_streamsPlaying = !m_playingStreams.empty();
}

inline void CSoftAE::ProcessSuspend()
{
bool sinkIsSuspended = false;

if (m_playingStreams.empty() && m_playing_sounds.empty() &&
!m_softSuspend && !g_advancedSettings.m_streamSilence)
{
m_softSuspend = true;
m_softSuspendTimer = XbmcThreads::SystemClockMillis() + 10000; //10.0 second delay for softSuspend
}

unsigned int curSystemClock = XbmcThreads::SystemClockMillis();

/* idle while in Suspend() state until Resume() called */
/* idle if nothing to play and user hasn't enabled */
/* continuous streaming (silent stream) in as.xml */
while ((m_isSuspended || (m_softSuspend && (curSystemClock > m_softSuspendTimer))) &&
m_running && !m_reOpen)
{
if (m_sink && !sinkIsSuspended)
{
/* put the sink in Suspend mode */
CExclusiveLock sinkLock(m_sinkLock);
if (!m_sink->SoftSuspend())
{
sinkIsSuspended = false; //sink cannot be suspended
m_softSuspend = false; //break suspend loop
break;
}
else
sinkIsSuspended = true; //sink has suspended processing
sinkLock.Leave();
}

/* idle for platform-defined time */
m_wake.WaitMSec(SOFTAE_IDLE_WAIT_MSEC);

/* check if we need to resume for stream or sound */
if (!m_isSuspended && (!m_playingStreams.empty() || !m_playing_sounds.empty()))
{
m_reOpen = !m_sink->SoftResume(); // sink returns false if it requires reinit
sinkIsSuspended = false; //sink processing data
m_softSuspend = false; //break suspend loop
break;
}
}
}

9 changes: 6 additions & 3 deletions xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.h
Expand Up @@ -120,6 +120,8 @@ class CSoftAE : public IThreadedAE
bool SetupEncoder(AEAudioFormat &format);
void Deinitialize();

inline void ProcessSuspend(); /* enter suspend state if nothing to play and sink allows */

inline void GetDeviceFriendlyName(std::string &device);

IAESink *GetSink(AEAudioFormat &desiredFormat, bool passthrough, std::string &device);
Expand All @@ -133,9 +135,10 @@ class CSoftAE : public IThreadedAE
bool m_stereoUpmix;

/* internal vars */
bool m_running, m_reOpen, m_isSuspended;
bool m_softSuspend; /* latches after last stream or sound played for timer below */
unsigned int m_softSuspendTimer; /* time in milliseconds to hold sink open before soft suspend */
bool m_running, m_reOpen;
bool m_isSuspended; /* engine suspended by external function to release audio context */
bool m_softSuspend; /* latches after last stream or sound played for timer below for idle */
unsigned int m_softSuspendTimer; /* time in milliseconds to hold sink open before soft suspend for idle */
CEvent m_reOpenEvent;
CEvent m_wake;

Expand Down
12 changes: 12 additions & 0 deletions xbmc/cores/AudioEngine/Interfaces/AESink.h
Expand Up @@ -87,5 +87,17 @@ class IAESink
This method sets the volume control, volume ranges from 0.0 to 1.0.
*/
virtual void SetVolume(float volume) {};

/*
Requests sink to prepare itself for a suspend state
@return false if sink cannot be suspended
*/
virtual bool SoftSuspend() {return false;};

/*
Notify sink to prepare to resume processing after suspend state
@return false if sink must be reinitialized
*/
virtual bool SoftResume() {return false;};
};

6 changes: 3 additions & 3 deletions xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
Expand Up @@ -489,9 +489,6 @@ unsigned int CAESinkALSA::AddPackets(uint8_t *data, unsigned int frames, bool ha
if (!m_pcm)
return 0;

if (snd_pcm_state(m_pcm) == SND_PCM_STATE_PREPARED)
snd_pcm_start(m_pcm);

int ret;

ret = snd_pcm_avail(m_pcm);
Expand Down Expand Up @@ -520,6 +517,9 @@ unsigned int CAESinkALSA::AddPackets(uint8_t *data, unsigned int frames, bool ha
}
}

if ( ret > 0 && snd_pcm_state(m_pcm) == SND_PCM_STATE_PREPARED)
snd_pcm_start(m_pcm);

return ret;
}

Expand Down
24 changes: 23 additions & 1 deletion xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp
Expand Up @@ -331,7 +331,8 @@ void CAESinkWASAPI::Deinitialize()
{
try
{
m_pAudioClient->Stop();
m_pAudioClient->Stop(); //stop the audio output
m_pAudioClient->Reset(); //flush buffer and reset audio clock stream position
}
catch (...)
{
Expand Down Expand Up @@ -537,6 +538,27 @@ unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames, bool
return NumFramesRequested;
}

bool CAESinkWASAPI::SoftSuspend()
{
/* Sink has been asked to suspend output - we release audio */
/* device as we are in exclusive mode and thus allow external */
/* audio sources to play. This requires us to reinitialize */
/* on resume. */

Deinitialize();

return true;
}

bool CAESinkWASAPI::SoftResume()
{
/* Sink asked to resume output. To release audio device in */
/* exclusive mode we release the device context and therefore */
/* must reinitialize. Return false to force re-init by engine */

return false;
}

void CAESinkWASAPI::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList)
{
IMMDeviceEnumerator* pEnumerator = NULL;
Expand Down
3 changes: 3 additions & 0 deletions xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h
Expand Up @@ -43,6 +43,8 @@ class CAESinkWASAPI : public IAESink
virtual double GetCacheTime ();
virtual double GetCacheTotal ();
virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
virtual bool SoftSuspend ();
virtual bool SoftResume ();
static void EnumerateDevicesEx (AEDeviceInfoList &deviceInfoList);
private:
bool InitializeExclusive(AEAudioFormat &format);
Expand Down Expand Up @@ -70,6 +72,7 @@ class CAESinkWASAPI : public IAESink

bool m_running;
bool m_initialized;
bool m_isSuspended; /* sink is in a suspended state - release audio device */
bool m_isDirty; /* sink output failed - needs re-init or new device */

unsigned int m_uiBufferLen; /* wasapi endpoint buffer size, in frames */
Expand Down

0 comments on commit f528cd3

Please sign in to comment.