mirror of
https://github.com/OpenMW/openmw.git
synced 2025-04-30 20:11:23 +00:00
Merge pull request #2749 from akortunov/sound_pause
Pause audio and video when the game is minimized
This commit is contained in:
commit
d3b898de88
11 changed files with 129 additions and 17 deletions
|
@ -244,6 +244,7 @@
|
||||||
Feature #4882: Support for NiPalette node
|
Feature #4882: Support for NiPalette node
|
||||||
Feature #4887: Add openmw command option to set initial random seed
|
Feature #4887: Add openmw command option to set initial random seed
|
||||||
Feature #4890: Make Distant Terrain configurable
|
Feature #4890: Make Distant Terrain configurable
|
||||||
|
Feature #4944: Pause audio when OpenMW is minimized
|
||||||
Feature #4958: Support eight blood types
|
Feature #4958: Support eight blood types
|
||||||
Feature #4962: Add casting animations for magic items
|
Feature #4962: Add casting animations for magic items
|
||||||
Feature #4968: Scalable UI widget skins
|
Feature #4968: Scalable UI widget skins
|
||||||
|
|
|
@ -96,7 +96,12 @@ bool OMW::Engine::frame(float frametime)
|
||||||
// If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures (fixed in MyGUI 3.3.2),
|
// If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures (fixed in MyGUI 3.3.2),
|
||||||
// and destroyed widgets will not be deleted (not fixed yet, https://github.com/MyGUI/mygui/issues/21)
|
// and destroyed widgets will not be deleted (not fixed yet, https://github.com/MyGUI/mygui/issues/21)
|
||||||
if (!mEnvironment.getInputManager()->isWindowVisible())
|
if (!mEnvironment.getInputManager()->isWindowVisible())
|
||||||
|
{
|
||||||
|
mEnvironment.getSoundManager()->pausePlayback();
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mEnvironment.getSoundManager()->resumePlayback();
|
||||||
|
|
||||||
// sound
|
// sound
|
||||||
if (mUseSound)
|
if (mUseSound)
|
||||||
|
|
|
@ -14,6 +14,14 @@ namespace MWWorld
|
||||||
|
|
||||||
namespace MWSound
|
namespace MWSound
|
||||||
{
|
{
|
||||||
|
// Each entry excepts of MaxCount should be used only in one place
|
||||||
|
enum BlockerType
|
||||||
|
{
|
||||||
|
VideoPlayback,
|
||||||
|
|
||||||
|
MaxCount
|
||||||
|
};
|
||||||
|
|
||||||
class Sound;
|
class Sound;
|
||||||
class Stream;
|
class Stream;
|
||||||
struct Sound_Decoder;
|
struct Sound_Decoder;
|
||||||
|
@ -168,12 +176,15 @@ namespace MWBase
|
||||||
///< Is the given sound currently playing on the given object?
|
///< Is the given sound currently playing on the given object?
|
||||||
/// If you want to check if sound played with playSound is playing, use empty Ptr
|
/// If you want to check if sound played with playSound is playing, use empty Ptr
|
||||||
|
|
||||||
virtual void pauseSounds(int types=static_cast<int>(Type::Mask)) = 0;
|
virtual void pauseSounds(MWSound::BlockerType blocker, int types=int(Type::Mask)) = 0;
|
||||||
///< Pauses all currently playing sounds, including music.
|
///< Pauses all currently playing sounds, including music.
|
||||||
|
|
||||||
virtual void resumeSounds(int types=static_cast<int>(Type::Mask)) = 0;
|
virtual void resumeSounds(MWSound::BlockerType blocker) = 0;
|
||||||
///< Resumes all previously paused sounds.
|
///< Resumes all previously paused sounds.
|
||||||
|
|
||||||
|
virtual void pausePlayback() = 0;
|
||||||
|
virtual void resumePlayback() = 0;
|
||||||
|
|
||||||
virtual void update(float duration) = 0;
|
virtual void update(float duration) = 0;
|
||||||
|
|
||||||
virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up, bool underwater) = 0;
|
virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up, bool underwater) = 0;
|
||||||
|
|
|
@ -76,6 +76,21 @@ void VideoWidget::stop()
|
||||||
mPlayer->close();
|
mPlayer->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VideoWidget::pause()
|
||||||
|
{
|
||||||
|
mPlayer->pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoWidget::resume()
|
||||||
|
{
|
||||||
|
mPlayer->play();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VideoWidget::isPaused() const
|
||||||
|
{
|
||||||
|
return mPlayer->isPaused();
|
||||||
|
}
|
||||||
|
|
||||||
bool VideoWidget::hasAudioStream()
|
bool VideoWidget::hasAudioStream()
|
||||||
{
|
{
|
||||||
return mPlayer->hasAudioStream();
|
return mPlayer->hasAudioStream();
|
||||||
|
|
|
@ -47,6 +47,10 @@ namespace MWGui
|
||||||
/// Stop video and free resources (done automatically on destruction)
|
/// Stop video and free resources (done automatically on destruction)
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
|
void pause();
|
||||||
|
void resume();
|
||||||
|
bool isPaused() const;
|
||||||
|
|
||||||
/// Adjust the coordinates of this video widget relative to its parent,
|
/// Adjust the coordinates of this video widget relative to its parent,
|
||||||
/// based on the dimensions of the playing video.
|
/// based on the dimensions of the playing video.
|
||||||
/// @param stretch Stretch the video to fill the whole screen? If false,
|
/// @param stretch Stretch the video to fill the whole screen? If false,
|
||||||
|
|
|
@ -1893,9 +1893,10 @@ namespace MWGui
|
||||||
setCursorVisible(false);
|
setCursorVisible(false);
|
||||||
|
|
||||||
if (mVideoWidget->hasAudioStream())
|
if (mVideoWidget->hasAudioStream())
|
||||||
MWBase::Environment::get().getSoundManager()->pauseSounds(
|
MWBase::Environment::get().getSoundManager()->pauseSounds(MWSound::VideoPlayback,
|
||||||
~MWSound::Type::Movie & MWSound::Type::Mask
|
~MWSound::Type::Movie & MWSound::Type::Mask
|
||||||
);
|
);
|
||||||
|
|
||||||
osg::Timer frameTimer;
|
osg::Timer frameTimer;
|
||||||
while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest())
|
while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest())
|
||||||
{
|
{
|
||||||
|
@ -1905,9 +1906,15 @@ namespace MWGui
|
||||||
MWBase::Environment::get().getInputManager()->update(dt, true, false);
|
MWBase::Environment::get().getInputManager()->update(dt, true, false);
|
||||||
|
|
||||||
if (!MWBase::Environment::get().getInputManager()->isWindowVisible())
|
if (!MWBase::Environment::get().getInputManager()->isWindowVisible())
|
||||||
|
{
|
||||||
|
mVideoWidget->pause();
|
||||||
OpenThreads::Thread::microSleep(5000);
|
OpenThreads::Thread::microSleep(5000);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (mVideoWidget->isPaused())
|
||||||
|
mVideoWidget->resume();
|
||||||
|
|
||||||
mViewer->eventTraversal();
|
mViewer->eventTraversal();
|
||||||
mViewer->updateTraversal();
|
mViewer->updateTraversal();
|
||||||
mViewer->renderingTraversals();
|
mViewer->renderingTraversals();
|
||||||
|
@ -1921,7 +1928,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
mVideoWidget->stop();
|
mVideoWidget->stop();
|
||||||
|
|
||||||
MWBase::Environment::get().getSoundManager()->resumeSounds();
|
MWBase::Environment::get().getSoundManager()->resumeSounds(MWSound::VideoPlayback);
|
||||||
|
|
||||||
setKeyFocusWidget(oldKeyFocus);
|
setKeyFocusWidget(oldKeyFocus);
|
||||||
|
|
||||||
|
|
|
@ -1454,6 +1454,38 @@ void OpenAL_Output::pauseSounds(int types)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenAL_Output::pauseActiveDevice()
|
||||||
|
{
|
||||||
|
if (mDevice == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(alcIsExtensionPresent(mDevice, "ALC_SOFT_PAUSE_DEVICE"))
|
||||||
|
{
|
||||||
|
LPALCDEVICEPAUSESOFT alcDevicePauseSOFT = 0;
|
||||||
|
getALCFunc(alcDevicePauseSOFT, mDevice, "alcDevicePauseSOFT");
|
||||||
|
alcDevicePauseSOFT(mDevice);
|
||||||
|
getALCError(mDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
alListenerf(AL_GAIN, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenAL_Output::resumeActiveDevice()
|
||||||
|
{
|
||||||
|
if (mDevice == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(alcIsExtensionPresent(mDevice, "ALC_SOFT_PAUSE_DEVICE"))
|
||||||
|
{
|
||||||
|
LPALCDEVICERESUMESOFT alcDeviceResumeSOFT = 0;
|
||||||
|
getALCFunc(alcDeviceResumeSOFT, mDevice, "alcDeviceResumeSOFT");
|
||||||
|
alcDeviceResumeSOFT(mDevice);
|
||||||
|
getALCError(mDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
alListenerf(AL_GAIN, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
void OpenAL_Output::resumeSounds(int types)
|
void OpenAL_Output::resumeSounds(int types)
|
||||||
{
|
{
|
||||||
std::vector<ALuint> sources;
|
std::vector<ALuint> sources;
|
||||||
|
|
|
@ -92,6 +92,9 @@ namespace MWSound
|
||||||
virtual void pauseSounds(int types);
|
virtual void pauseSounds(int types);
|
||||||
virtual void resumeSounds(int types);
|
virtual void resumeSounds(int types);
|
||||||
|
|
||||||
|
virtual void pauseActiveDevice();
|
||||||
|
virtual void resumeActiveDevice();
|
||||||
|
|
||||||
OpenAL_Output(SoundManager &mgr);
|
OpenAL_Output(SoundManager &mgr);
|
||||||
virtual ~OpenAL_Output();
|
virtual ~OpenAL_Output();
|
||||||
};
|
};
|
||||||
|
|
|
@ -62,6 +62,9 @@ namespace MWSound
|
||||||
virtual void pauseSounds(int types) = 0;
|
virtual void pauseSounds(int types) = 0;
|
||||||
virtual void resumeSounds(int types) = 0;
|
virtual void resumeSounds(int types) = 0;
|
||||||
|
|
||||||
|
virtual void pauseActiveDevice() = 0;
|
||||||
|
virtual void resumeActiveDevice() = 0;
|
||||||
|
|
||||||
Sound_Output& operator=(const Sound_Output &rhs);
|
Sound_Output& operator=(const Sound_Output &rhs);
|
||||||
Sound_Output(const Sound_Output &rhs);
|
Sound_Output(const Sound_Output &rhs);
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,9 @@ namespace MWSound
|
||||||
, mListenerPos(0,0,0)
|
, mListenerPos(0,0,0)
|
||||||
, mListenerDir(1,0,0)
|
, mListenerDir(1,0,0)
|
||||||
, mListenerUp(0,0,1)
|
, mListenerUp(0,0,1)
|
||||||
, mPausedSoundTypes(0)
|
|
||||||
, mUnderwaterSound(nullptr)
|
, mUnderwaterSound(nullptr)
|
||||||
, mNearWaterSound(nullptr)
|
, mNearWaterSound(nullptr)
|
||||||
|
, mPlaybackPaused(false)
|
||||||
{
|
{
|
||||||
mMasterVolume = Settings::Manager::getFloat("master volume", "Sound");
|
mMasterVolume = Settings::Manager::getFloat("master volume", "Sound");
|
||||||
mMasterVolume = std::min(std::max(mMasterVolume, 0.0f), 1.0f);
|
mMasterVolume = std::min(std::max(mMasterVolume, 0.0f), 1.0f);
|
||||||
|
@ -857,27 +857,52 @@ namespace MWSound
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoundManager::pauseSounds(BlockerType blocker, int types)
|
||||||
void SoundManager::pauseSounds(int types)
|
|
||||||
{
|
{
|
||||||
if(mOutput->isInitialized())
|
if(mOutput->isInitialized())
|
||||||
{
|
{
|
||||||
|
if (mPausedSoundTypes[blocker] != 0)
|
||||||
|
resumeSounds(blocker);
|
||||||
|
|
||||||
types = types & Type::Mask;
|
types = types & Type::Mask;
|
||||||
mOutput->pauseSounds(types);
|
mOutput->pauseSounds(types);
|
||||||
mPausedSoundTypes |= types;
|
mPausedSoundTypes[blocker] = types;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::resumeSounds(int types)
|
void SoundManager::resumeSounds(BlockerType blocker)
|
||||||
{
|
{
|
||||||
if(mOutput->isInitialized())
|
if(mOutput->isInitialized())
|
||||||
{
|
{
|
||||||
types = types & Type::Mask & mPausedSoundTypes;
|
mPausedSoundTypes[blocker] = 0;
|
||||||
|
int types = int(Type::Mask);
|
||||||
|
for (int currentBlocker = 0; currentBlocker < BlockerType::MaxCount; currentBlocker++)
|
||||||
|
{
|
||||||
|
if (currentBlocker != blocker)
|
||||||
|
types &= ~mPausedSoundTypes[currentBlocker];
|
||||||
|
}
|
||||||
|
|
||||||
mOutput->resumeSounds(types);
|
mOutput->resumeSounds(types);
|
||||||
mPausedSoundTypes &= ~types;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoundManager::pausePlayback()
|
||||||
|
{
|
||||||
|
if (mPlaybackPaused)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mPlaybackPaused = true;
|
||||||
|
mOutput->pauseActiveDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundManager::resumePlayback()
|
||||||
|
{
|
||||||
|
if (!mPlaybackPaused)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mPlaybackPaused = false;
|
||||||
|
mOutput->resumeActiveDevice();
|
||||||
|
}
|
||||||
|
|
||||||
void SoundManager::updateRegionSound(float duration)
|
void SoundManager::updateRegionSound(float duration)
|
||||||
{
|
{
|
||||||
|
@ -1201,7 +1226,7 @@ namespace MWSound
|
||||||
|
|
||||||
void SoundManager::update(float duration)
|
void SoundManager::update(float duration)
|
||||||
{
|
{
|
||||||
if(!mOutput->isInitialized())
|
if(!mOutput->isInitialized() || mPlaybackPaused)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
updateSounds(duration);
|
updateSounds(duration);
|
||||||
|
@ -1399,5 +1424,7 @@ namespace MWSound
|
||||||
mUnusedStreams.push_back(sound);
|
mUnusedStreams.push_back(sound);
|
||||||
}
|
}
|
||||||
mActiveTracks.clear();
|
mActiveTracks.clear();
|
||||||
|
mPlaybackPaused = false;
|
||||||
|
std::fill(std::begin(mPausedSoundTypes), std::end(mPausedSoundTypes), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,11 +107,14 @@ namespace MWSound
|
||||||
osg::Vec3f mListenerDir;
|
osg::Vec3f mListenerDir;
|
||||||
osg::Vec3f mListenerUp;
|
osg::Vec3f mListenerUp;
|
||||||
|
|
||||||
int mPausedSoundTypes;
|
int mPausedSoundTypes[BlockerType::MaxCount] = {};
|
||||||
|
|
||||||
Sound *mUnderwaterSound;
|
Sound *mUnderwaterSound;
|
||||||
Sound *mNearWaterSound;
|
Sound *mNearWaterSound;
|
||||||
|
|
||||||
|
std::string mNextMusic;
|
||||||
|
bool mPlaybackPaused;
|
||||||
|
|
||||||
Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound);
|
Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound);
|
||||||
|
|
||||||
Sound_Buffer *lookupSound(const std::string &soundId) const;
|
Sound_Buffer *lookupSound(const std::string &soundId) const;
|
||||||
|
@ -134,8 +137,6 @@ namespace MWSound
|
||||||
void updateWaterSound(float duration);
|
void updateWaterSound(float duration);
|
||||||
void updateMusic(float duration);
|
void updateMusic(float duration);
|
||||||
|
|
||||||
std::string mNextMusic;
|
|
||||||
|
|
||||||
float volumeFromType(Type type) const;
|
float volumeFromType(Type type) const;
|
||||||
|
|
||||||
SoundManager(const SoundManager &rhs);
|
SoundManager(const SoundManager &rhs);
|
||||||
|
@ -244,12 +245,15 @@ namespace MWSound
|
||||||
virtual bool getSoundPlaying(const MWWorld::ConstPtr &reference, const std::string& soundId) const;
|
virtual bool getSoundPlaying(const MWWorld::ConstPtr &reference, const std::string& soundId) const;
|
||||||
///< Is the given sound currently playing on the given object?
|
///< Is the given sound currently playing on the given object?
|
||||||
|
|
||||||
virtual void pauseSounds(int types);
|
virtual void pauseSounds(MWSound::BlockerType blocker, int types=int(Type::Mask));
|
||||||
///< Pauses all currently playing sounds, including music.
|
///< Pauses all currently playing sounds, including music.
|
||||||
|
|
||||||
virtual void resumeSounds(int types);
|
virtual void resumeSounds(MWSound::BlockerType blocker);
|
||||||
///< Resumes all previously paused sounds.
|
///< Resumes all previously paused sounds.
|
||||||
|
|
||||||
|
virtual void pausePlayback();
|
||||||
|
virtual void resumePlayback();
|
||||||
|
|
||||||
virtual void update(float duration);
|
virtual void update(float duration);
|
||||||
|
|
||||||
virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up, bool underwater);
|
virtual void setListenerPosDir(const osg::Vec3f &pos, const osg::Vec3f &dir, const osg::Vec3f &up, bool underwater);
|
||||||
|
|
Loading…
Reference in a new issue