From e77e93f7794ba13865b353bc78fba74e882a8444 Mon Sep 17 00:00:00 2001 From: kervala Date: Tue, 17 Aug 2010 23:02:47 +0200 Subject: [PATCH] Fixed: infinite loop in ogg vorbis streaming (negative ov_read result means an error) --- .../src/sound/driver/music_buffer_vorbis.cpp | 57 ++++++++++++------- .../sound/driver/openal/music_channel_al.cpp | 5 +- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/code/nel/src/sound/driver/music_buffer_vorbis.cpp b/code/nel/src/sound/driver/music_buffer_vorbis.cpp index 3624f98d7..ed5f5a801 100644 --- a/code/nel/src/sound/driver/music_buffer_vorbis.cpp +++ b/code/nel/src/sound/driver/music_buffer_vorbis.cpp @@ -120,40 +120,59 @@ uint32 CMusicBufferVorbis::getRequiredBytes() uint32 CMusicBufferVorbis::getNextBytes(uint8 *buffer, uint32 minimum, uint32 maximum) { - int current_section = 0; // ??? + sint current_section = 0; // ??? if (_IsMusicEnded) return 0; nlassert(minimum <= maximum); // can't have this.. uint32 bytes_read = 0; do { // signed 16-bit or unsigned 8-bit little-endian samples - int br = ov_read(&_OggVorbisFile, (char *)&buffer[bytes_read], maximum - bytes_read, + sint br = ov_read(&_OggVorbisFile, (char *)&buffer[bytes_read], maximum - bytes_read, 0, // Specifies big or little endian byte packing. 0 for little endian, 1 for b ig endian. Typical value is 0. getBitsPerSample() == 8 ? 1 : 2, getBitsPerSample() == 8 ? 0 : 1, // Signed or unsigned data. 0 for unsigned, 1 for signed. Typically 1. ¤t_section); // nlinfo(NLSOUND_XAUDIO2_PREFIX "current_section: %i", current_section); - if (br <= 0) - { - if (br == 0) + if (br > 0) + { + bytes_read += (uint32)br; + } + else if (br == 0) // EOF + { + if (_Loop) { - if (_Loop) - { - ov_pcm_seek(&_OggVorbisFile, 0); - //_Stream->seek(0, NLMISC::IStream::begin); - } - else - { - _IsMusicEnded = true; - break; - } + ov_pcm_seek(&_OggVorbisFile, 0); + //_Stream->seek(0, NLMISC::IStream::begin); } - else + else { - nlwarning("ov_read: %i", br); + _IsMusicEnded = true; + break; } } - else bytes_read += (uint32)br; + else + { + // error + switch(br) + { + case OV_HOLE: + nlwarning("ov_read returned OV_HOLE"); + break; + + case OV_EINVAL: + nlwarning("ov_read returned OV_EINVAL"); + break; + + case OV_EBADLINK: + nlwarning("ov_read returned OV_EBADLINK"); + break; + + default: + nlwarning("ov_read returned %d", br); + } + + return 0; + } } while (bytes_read < minimum); return bytes_read; } @@ -161,7 +180,7 @@ uint32 CMusicBufferVorbis::getNextBytes(uint8 *buffer, uint32 minimum, uint32 ma uint8 CMusicBufferVorbis::getChannels() { vorbis_info *vi = ov_info(&_OggVorbisFile, -1); - return (uint16)vi->channels; + return (uint8)vi->channels; } uint32 CMusicBufferVorbis::getSamplesPerSec() diff --git a/code/nel/src/sound/driver/openal/music_channel_al.cpp b/code/nel/src/sound/driver/openal/music_channel_al.cpp index 317d8fff9..d93105a92 100644 --- a/code/nel/src/sound/driver/openal/music_channel_al.cpp +++ b/code/nel/src/sound/driver/openal/music_channel_al.cpp @@ -83,7 +83,7 @@ bool CMusicChannelAL::fillBuffer(IBuffer *buffer, uint length) uint32 size = _MusicBuffer->getNextBytes(tmp, length, length); buffer->unlock(size); - return true; + return size > 0; } /// Use buffer format from IMusicBuffer @@ -128,7 +128,8 @@ void CMusicChannelAL::run() // fill buffers for(uint i = 0; i < buffers.size(); ++i) { - fillBuffer(buffers[i], _Source->getStreamingBufferSize()); + if (!fillBuffer(buffers[i], _Source->getStreamingBufferSize())) + break; // add buffer to streaming buffers queue _Source->submitStreamingBuffer(buffers[i]);