From 65096786e13bea0fcfc5b22fac593b89acd9f61c Mon Sep 17 00:00:00 2001 From: kaetemi Date: Thu, 12 Apr 2012 00:25:26 +0200 Subject: [PATCH] Changed: #795 #1460 Make sure the streaming thread safely stops in all cases --- .../include/nel/sound/stream_file_source.h | 2 +- code/nel/include/nel/sound/stream_source.h | 3 + code/nel/src/sound/source_music_channel.cpp | 3 + code/nel/src/sound/stream_file_source.cpp | 72 +++++++++++++++---- code/nel/src/sound/stream_source.cpp | 20 ++++-- 5 files changed, 80 insertions(+), 20 deletions(-) diff --git a/code/nel/include/nel/sound/stream_file_source.h b/code/nel/include/nel/sound/stream_file_source.h index 4bce66719..64c2d5228 100644 --- a/code/nel/include/nel/sound/stream_file_source.h +++ b/code/nel/include/nel/sound/stream_file_source.h @@ -86,7 +86,7 @@ public: private: void prepareDecoder(); - void bufferMore(uint bytes); + inline bool bufferMore(uint bytes); private: CStreamFileSource(const CStreamFileSource &); diff --git a/code/nel/include/nel/sound/stream_source.h b/code/nel/include/nel/sound/stream_source.h index 1c94a5b7a..40ed82e11 100644 --- a/code/nel/include/nel/sound/stream_source.h +++ b/code/nel/include/nel/sound/stream_source.h @@ -55,6 +55,9 @@ public: virtual void setLooping(bool l); /// Play virtual void play(); +protected: + void stopInt(); +public: /// Stop playing virtual void stop(); /// Get playing state. Return false even if the source has stopped on its own. diff --git a/code/nel/src/sound/source_music_channel.cpp b/code/nel/src/sound/source_music_channel.cpp index 4395f3b5e..bd8f152e0 100644 --- a/code/nel/src/sound/source_music_channel.cpp +++ b/code/nel/src/sound/source_music_channel.cpp @@ -60,6 +60,9 @@ bool CSourceMusicChannel::play(const std::string &filepath, bool async, bool loo m_Sound.setMusicFilePath(filepath, async, loop); m_Source = new CStreamFileSource(&m_Sound, false, NULL, NULL, NULL, NULL); + m_Source->setSourceRelativeMode(true); + m_Source->setPos(NLMISC::CVector::Null); + m_Source->setRelativeGain(m_Gain); m_Source->play(); diff --git a/code/nel/src/sound/stream_file_source.cpp b/code/nel/src/sound/stream_file_source.cpp index 6a8c6b7d2..2b7bd94ee 100644 --- a/code/nel/src/sound/stream_file_source.cpp +++ b/code/nel/src/sound/stream_file_source.cpp @@ -65,13 +65,18 @@ void CStreamFileSource::play() if (m_Thread->isRunning() && m_WaitingForPlay) { - nldebug("play waiting %s", getStreamFileSound()->getFilePath().c_str()); if (m_NextBuffer || !m_FreeBuffers) { + nldebug("play waiting, play stream %s", getStreamFileSound()->getFilePath().c_str()); CStreamSource::play(); + if (!_Playing && !m_WaitingForPlay) + { + nldebug("playing not possible or necessary for some reason"); + } } else { + nldebug("play waiting, hop onto waiting list %s", getStreamFileSound()->getFilePath().c_str()); m_WaitingForPlay = true; CAudioMixerUser *mixer = CAudioMixerUser::instance(); mixer->addSourceWaitingForPlay(this); @@ -79,7 +84,7 @@ void CStreamFileSource::play() } else if (!_Playing) { - nldebug("play waiting %s", getStreamFileSound()->getFilePath().c_str()); + nldebug("play go %s", getStreamFileSound()->getFilePath().c_str()); if (!m_WaitingForPlay) { // thread may be stopping from stop call @@ -98,12 +103,18 @@ void CStreamFileSource::play() if (!getStreamFileSound()->getAsync()) { // wait until at least one buffer is ready - while (!(m_NextBuffer || !m_FreeBuffers) && m_WaitingForPlay) - NLMISC::nlSleep(10); - CStreamSource::play(); - if (!_Playing) + while (!(m_NextBuffer || !m_FreeBuffers) && m_WaitingForPlay && m_Thread->isRunning()) { - nlwarning("Failed to synchronously start playing a file stream source. This happens when all physical tracks are in use. Use a Highest Priority sound"); + nldebug("wait buffer"); + NLMISC::nlSleep(100); + } + if (m_WaitingForPlay && m_Thread->isRunning()) + { + CStreamSource::play(); + if (!_Playing) + { + nlwarning("Failed to synchronously start playing a file stream source. This happens when all physical tracks are in use. Use a Highest Priority sound"); + } } } else @@ -135,7 +146,19 @@ void CStreamFileSource::stop() { nldebug("stop %s", getStreamFileSound()->getFilePath().c_str()); - CStreamSource::stop(); + CStreamSource::stopInt(); + + nldebug("stopInt ok"); + + if (_Spawn) + { + if (_SpawnEndCb != NULL) + _SpawnEndCb(this, _CbUserParam); + m_Thread->wait(); + delete this; + } + + nldebug("stop ok"); // thread will check _Playing to stop } @@ -229,30 +252,41 @@ void CStreamFileSource::prepareDecoder() this->preAllocate(bytes * 2); } -void CStreamFileSource::bufferMore(uint bytes) // buffer from bytes (minimum) to bytes * 2 (maximum) +inline bool CStreamFileSource::bufferMore(uint bytes) // buffer from bytes (minimum) to bytes * 2 (maximum) { uint8 *buffer = this->lock(bytes * 2); if (buffer) { uint32 result = m_AudioDecoder->getNextBytes(buffer, bytes, bytes * 2); this->unlock(result); + return true; } + return false; } void CStreamFileSource::run() { - nldebug("run"); + nldebug("run %s", getStreamFileSound()->getFilePath().c_str()); + uint dumpI = 0; bool looping = _Looping; if (getStreamFileSound()->getAsync()) prepareDecoder(); uint samples, bytes; this->getRecommendedBufferSize(samples, bytes); - bufferMore(bytes); + uint32 recSleep = 40; + uint32 doSleep = 10; while (_Playing || m_WaitingForPlay) { if (!m_AudioDecoder->isMusicEnded()) { + ++dumpI; + if (!(dumpI % 100)) + { + nldebug("buffer %s %s %s", _Playing ? "PLAYING" : "NP", m_WaitingForPlay ? "WAITING" : "NW", getStreamFileSound()->getFilePath().c_str()); + nldebug("gain %f", hasPhysicalSource() ? getPhysicalSource()->getGain() : -1.0f); + } + bool newLooping = _Looping; if (looping != newLooping) { @@ -260,14 +294,19 @@ void CStreamFileSource::run() looping = newLooping; } - bufferMore(bytes); - NLMISC::nlSleep(this->getRecommendedSleepTime()); + // reduce sleeping time if nothing was buffered + if (bufferMore(bytes)) recSleep = doSleep = this->getRecommendedSleepTime(); + else doSleep = recSleep >> 2; // /4 + NLMISC::nlSleep(doSleep); } else { // wait until done playing buffers - while (this->hasFilledBuffersAvailable()) + while (this->hasFilledBuffersAvailable() && (_Playing || m_WaitingForPlay)) + { + nldebug("music ended, wait until done %s", getStreamFileSound()->getFilePath().c_str()); NLMISC::nlSleep(40); + } // stop the physical source // if (hasPhysicalSource()) // getPhysicalSource()->stop(); @@ -284,6 +323,11 @@ void CStreamFileSource::run() delete m_AudioDecoder; m_AudioDecoder = NULL; } + // drop buffers + m_FreeBuffers = 3; + m_NextBuffer = 0; + + nldebug("run end %s", getStreamFileSound()->getFilePath().c_str()); } } /* namespace NLSOUND */ diff --git a/code/nel/src/sound/stream_source.cpp b/code/nel/src/sound/stream_source.cpp index 1cd1ddcbc..c71e7d8e2 100644 --- a/code/nel/src/sound/stream_source.cpp +++ b/code/nel/src/sound/stream_source.cpp @@ -160,7 +160,8 @@ void CStreamSource::play() _SpawnEndCb(this, _CbUserParam); delete this; } - // nldebug("CStreamSource %p : play FAILED !", (CAudioMixerUser::IMixerEvent*)this); + nldebug("CStreamSource %p : play FAILED, source is too far away !", (CAudioMixerUser::IMixerEvent*)this); + m_WaitingForPlay = false; return; } @@ -216,6 +217,7 @@ void CStreamSource::play() _SpawnEndCb(this, _CbUserParam); delete this; } + m_WaitingForPlay = false; return; } } @@ -232,8 +234,7 @@ void CStreamSource::play() #endif } -/// Stop playing -void CStreamSource::stop() +void CStreamSource::stopInt() { CAutoMutex autoMutex(m_BufferMutex); @@ -248,7 +249,10 @@ void CStreamSource::stop() } if (!_Playing) + { + m_WaitingForPlay = false; return; + } if (hasPhysicalSource()) releasePhysicalSource(); @@ -258,14 +262,20 @@ void CStreamSource::stop() m_FreeBuffers = 3; m_NextBuffer = 0; + m_WaitingForPlay = false; +} + +/// Stop playing +void CStreamSource::stop() +{ + stopInt(); + if (_Spawn) { if (_SpawnEndCb != NULL) _SpawnEndCb(this, _CbUserParam); delete this; } - - m_WaitingForPlay = false; } void CStreamSource::setPos(const NLMISC::CVector& pos)