From 55963118512448c04dc78ed33e56c220413cfca9 Mon Sep 17 00:00:00 2001 From: Damian Huckle Date: Wed, 3 Oct 2012 19:36:37 -0400 Subject: [PATCH 1/5] [AE][AESink] Add SoftSuspend/Resume virtual functions to AESink.h --- xbmc/cores/AudioEngine/Interfaces/AESink.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/xbmc/cores/AudioEngine/Interfaces/AESink.h b/xbmc/cores/AudioEngine/Interfaces/AESink.h index be1baa66eb002..ddabd69c7c9c1 100644 --- a/xbmc/cores/AudioEngine/Interfaces/AESink.h +++ b/xbmc/cores/AudioEngine/Interfaces/AESink.h @@ -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 true;}; + + /* + Notify sink to prepare to resume processing after suspend state + @return false if sink must be reinitialized + */ + virtual bool SoftResume() {return true;}; }; From 579b35e9bd4195598c3e816411bae78cb46b833b Mon Sep 17 00:00:00 2001 From: Damian Huckle Date: Thu, 4 Oct 2012 21:16:09 -0400 Subject: [PATCH 2/5] [AE][SoftAE] Use abstracted sink SoftSuspend/Resume functions instead of sink teardown --- .../AudioEngine/Engines/SoftAE/SoftAE.cpp | 78 ++++++++++++------- .../cores/AudioEngine/Engines/SoftAE/SoftAE.h | 9 ++- 2 files changed, 56 insertions(+), 31 deletions(-) diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp index 8e7a1f9ae1bec..43ed058fc52b4 100644 --- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp +++ b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp @@ -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) @@ -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; + } + } +} + diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.h b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.h index bb21d7d8746b7..a91e42fe6e7a3 100644 --- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.h +++ b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.h @@ -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); @@ -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; From a7a09602a7b20f9c8f08289b30c8b424ea83878f Mon Sep 17 00:00:00 2001 From: Damian Huckle Date: Thu, 4 Oct 2012 21:17:44 -0400 Subject: [PATCH 3/5] [AE][WASAPI] Implement sink softSuspend/Resume functions to release exclusive mode context --- xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp | 24 ++++++++++++++++++- xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h | 3 +++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp index af994d93ebc94..8475d60f7e847 100644 --- a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp +++ b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp @@ -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 (...) { @@ -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; diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h index b5f6ce7bf8807..a0c567ae7b17d 100644 --- a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h +++ b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h @@ -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); @@ -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 */ From d54a8ad11d0fc708aa5ab270f7f899c61c742795 Mon Sep 17 00:00:00 2001 From: Damian Huckle Date: Thu, 22 Nov 2012 00:16:02 -0500 Subject: [PATCH 4/5] [AE][AESink] Set virtual sink suspend/resume functions to default to false - cannot be suspended --- xbmc/cores/AudioEngine/Interfaces/AESink.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xbmc/cores/AudioEngine/Interfaces/AESink.h b/xbmc/cores/AudioEngine/Interfaces/AESink.h index ddabd69c7c9c1..a67b860b41fbe 100644 --- a/xbmc/cores/AudioEngine/Interfaces/AESink.h +++ b/xbmc/cores/AudioEngine/Interfaces/AESink.h @@ -92,12 +92,12 @@ class IAESink Requests sink to prepare itself for a suspend state @return false if sink cannot be suspended */ - virtual bool SoftSuspend() {return true;}; + 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 true;}; + virtual bool SoftResume() {return false;}; }; From 2b41991e324d1cfdbf5202bc02c821df97953d89 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 20 Nov 2012 18:09:40 -0500 Subject: [PATCH 5/5] ae/alsa: fill buffer before starting the hardware --- xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp index d391595be8512..d180ff5a46a12 100644 --- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp @@ -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); @@ -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; }