SFML community forums

Help => Audio => Topic started by: Retrorage on December 20, 2019, 09:04:21 pm

Title: How to properly remove sfml::sound/music (AL lib: (EE) alc_cleanup: 1 device...)
Post by: Retrorage on December 20, 2019, 09:04:21 pm
So all the sounds and music work, however when I exit the program I get this warning (AL lib: (EE) alc_cleanup: 1 device not closed).

So I was able to resolve this warning for sfml::music by using "GameData->assets.music.~SoundSource();" before I exited the window. However I am not sure that is proper.

I cannot resolve this warning for sound objects.
This is how I load sound buffers in a class called assetManager.

void AssetManager::LoadSoundBuffer(const string name, std::string fileName) {
        sf::SoundBuffer sB;
        if (sB.loadFromFile(fileName))
            this->_soundBuffers[name] = sB;
        else
            std::cout << "\n Failed to load sound!";
   }
   //Music cannot be loadedaccroding to SFML documentation (due to music being long it will eat up a bunch of memory and this must
    //be loaded on the go in small chucks during runtime

   void AssetManager::RemoveSoundBuffer(const string name) {
      if (this->_soundBuffers.find(name) != _soundBuffers.end())
         _soundBuffers.erase(name);
   }

And I hold a sf::sound object as a private member in a class called menuState.

According to some of the other post I read, possible issues for this is that I am not letting the new thread sounds create, exit and remove their resources, before the program closes, or that my sound buffers are being removed before the sound gets removed.

Any suggestions on how I should go about this!
Title: Re: How to properly remove sfml::sound/music (AL lib: (EE) alc_cleanup: 1 device...)
Post by: Nexus on December 21, 2019, 05:19:31 pm
So I was able to resolve this warning for sfml::music by using "GameData->assets.music.~SoundSource();" before I exited the window. However I am not sure that is proper.
I'm sure it's not proper. ;)
In fact, calling destructors manually is undefined behavior (UB), if they are called again automatically.

        void AssetManager::RemoveSoundBuffer(const string name) {
                if (this->_soundBuffers.find(name) != _soundBuffers.end())
                        _soundBuffers.erase(name);
        }
I don't know what data structure _soundBuffers is -- but if it's a std::vector or std::deque, erasing one element will invalidate pointers to the erased element and all subsequent elements. Since every sf::Sound stores a pointer to a sf::SoundBuffer, you may trigger UB here as well, due to dangling pointers. A std::list or std::map would not have this problem, they are stable data structures.

It's relatively simple to get sound lifetimes right, you need to consider the following rules:
In case you want a readily available solution for managing resources like sf::SoundBuffer, you might be interested in my library Thor (here's a tutorial (https://bromeon.ch/libraries/thor/tutorials/v2.0/resources.html) which shows some examples).
Title: Re: How to properly remove sfml::sound/music (AL lib: (EE) alc_cleanup: 1 device...)
Post by: Retrorage on December 22, 2019, 04:43:06 am
So I had the soundbuffers stored in a std::map, and it turns out I did not need to call GameData->assets.music.~SoundSource(); at all.

But I was rolling through code thinking about

  • Every sf::SoundBuffer must outlive all the sf::Sound instances that refer to it.


And I found the error, and a pretty big one at that.
I had a dynamic object that had sf::sound member that was not being properly removed. Which was why, like you said, a sound object was outliving the soundbuffer it was refering too. Thanks a lot! Really big help!