Skip to content
New issue

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

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AE] Allow sink to decide how or if it can be suspended #1548

Merged
merged 5 commits into from Nov 30, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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()))
{

This comment was marked as spam.

This comment was marked as spam.

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;};

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

/*
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