From ce74c412978c8aebbe201d22a645f849ee848466 Mon Sep 17 00:00:00 2001 From: wraitii Date: Fri, 22 Jan 2021 12:50:05 +0000 Subject: [PATCH] Fix audio leak that resulted in openAL errors after a while. Sound items were only deleted after 'last play' when stopped, but they could also be left in 'paused' or 'initial' states, and were then not cleared until the game exits (effectively a memory leak). This affected particularly music & ambient sounds, which also used the most buffers(/memory). On MacOS (at least), this resulted in OpenAL errors & sound failures after a while playing the game, because MacOS has a max "in flight buffers" of 1024. Also clean up some control flow in CStreamItem Reported by: Eszett Thanks langbart for the consistent repro'. Fixes #5265 Differential Revision: https://code.wildfiregames.com/D3445 This was SVN commit r24762. --- source/soundmanager/items/CBufferItem.cpp | 6 +- source/soundmanager/items/CSoundItem.cpp | 6 +- source/soundmanager/items/CStreamItem.cpp | 76 +++++++++++------------ 3 files changed, 43 insertions(+), 45 deletions(-) diff --git a/source/soundmanager/items/CBufferItem.cpp b/source/soundmanager/items/CBufferItem.cpp index df236c2087..dba96531db 100644 --- a/source/soundmanager/items/CBufferItem.cpp +++ b/source/soundmanager/items/CBufferItem.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -79,8 +79,8 @@ bool CBufferItem::IdleTask() int proc_state; alGetSourcei(m_ALSource, AL_SOURCE_STATE, &proc_state); AL_CHECK; - m_ShouldBePlaying = (proc_state != AL_STOPPED); - return (proc_state != AL_STOPPED); + m_ShouldBePlaying = (proc_state != AL_STOPPED && proc_state != AL_INITIAL && proc_state != AL_PAUSED); + return m_ShouldBePlaying; } if (GetLooping()) diff --git a/source/soundmanager/items/CSoundItem.cpp b/source/soundmanager/items/CSoundItem.cpp index 8d864f31c7..512260179a 100644 --- a/source/soundmanager/items/CSoundItem.cpp +++ b/source/soundmanager/items/CSoundItem.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -57,8 +57,8 @@ bool CSoundItem::IdleTask() int proc_state; alGetSourcei(m_ALSource, AL_SOURCE_STATE, &proc_state); AL_CHECK; - m_ShouldBePlaying = (proc_state != AL_STOPPED); - return (proc_state != AL_STOPPED); + m_ShouldBePlaying = (proc_state != AL_STOPPED && proc_state != AL_INITIAL && proc_state != AL_PAUSED); + return m_ShouldBePlaying; } return true; } diff --git a/source/soundmanager/items/CStreamItem.cpp b/source/soundmanager/items/CStreamItem.cpp index 72e771a5dc..df44f0a5de 100644 --- a/source/soundmanager/items/CStreamItem.cpp +++ b/source/soundmanager/items/CStreamItem.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -67,50 +67,48 @@ bool CStreamItem::IdleTask() HandleFade(); AL_CHECK; - if (m_ALSource != 0) + if (m_ALSource == 0) + return true; + + int proc_state; + alGetSourcei(m_ALSource, AL_SOURCE_STATE, &proc_state); + AL_CHECK; + + if (proc_state == AL_STOPPED || proc_state == AL_PAUSED) + return !m_LastPlay; + + if (m_SoundData == nullptr) + return true; + + COggData* theData = (COggData*)m_SoundData; + + if (!theData->IsFileFinished()) { - int proc_state; - alGetSourcei(m_ALSource, AL_SOURCE_STATE, &proc_state); + int num_processed; + alGetSourcei(m_ALSource, AL_BUFFERS_PROCESSED, &num_processed); AL_CHECK; - if (proc_state == AL_STOPPED) + if (num_processed > 0) { - if (m_LastPlay) - return (proc_state != AL_STOPPED); - } - else if (m_SoundData != NULL) - { - COggData* theData = (COggData*)m_SoundData; - - if (! theData->IsFileFinished()) - { - int num_processed; - alGetSourcei(m_ALSource, AL_BUFFERS_PROCESSED, &num_processed); - AL_CHECK; - - if (num_processed > 0) - { - ALuint* al_buf = new ALuint[num_processed]; - alSourceUnqueueBuffers(m_ALSource, num_processed, al_buf); - AL_CHECK; - int didWrite = theData->FetchDataIntoBuffer(num_processed, al_buf); - alSourceQueueBuffers(m_ALSource, didWrite, al_buf); - AL_CHECK; - delete[] al_buf; - } - } - else if (GetLooping()) - { - theData->ResetFile(); - } - else - { - int num_processed; - alGetSourcei(m_ALSource, AL_BUFFERS_QUEUED, &num_processed); - m_ShouldBePlaying = ( num_processed == 0 ); - } + ALuint* al_buf = new ALuint[num_processed]; + alSourceUnqueueBuffers(m_ALSource, num_processed, al_buf); + AL_CHECK; + int didWrite = theData->FetchDataIntoBuffer(num_processed, al_buf); + alSourceQueueBuffers(m_ALSource, didWrite, al_buf); + AL_CHECK; + delete[] al_buf; } } + else if (GetLooping()) + { + theData->ResetFile(); + } + else + { + int num_processed; + alGetSourcei(m_ALSource, AL_BUFFERS_QUEUED, &num_processed); + m_ShouldBePlaying = ( num_processed == 0 ); + } AL_CHECK; return true; }