Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Re-check if sound device becomes available after failing  (Read 7045 times)

0 Members and 1 Guest are viewing this topic.

Jonny

  • Full Member
  • ***
  • Posts: 114
    • View Profile
    • Email
Re-check if sound device becomes available after failing
« on: November 03, 2015, 12:05:58 pm »
Not sure whether this is considered a bug or not, but I'm having an issue with how SFML handles audio when the device is temporarily unavailable. If the device is unavailable when the first Sound/Music instance is created, but then becomes available later on (or even straight away after that) sounds will still never work.

Here's an example to reproduce:

#include <SFML\Graphics.hpp>
#include <SFML\Audio.hpp>

int main()
{
        sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
        sf::CircleShape shape(100.f);
        shape.setFillColor(sf::Color::Green);

        //first music instance, this is where the device is initialised
        //disable sound device for this line
        sf::Music firstMusic;

        //second music instance,
        //make sure device is enabled from here onwards
        sf::Music secondMusic;

        while (window.isOpen())
        {
                sf::Event event;
                while (window.pollEvent(event))
                {
                        if (event.type == sf::Event::Closed)
                                window.close();
                        if (event.type == sf::Event::KeyPressed)
                        {
                                if (event.key.code == sf::Keyboard::Space)
                                {
                                        //re-open the sound and play
                                        secondMusic.openFromFile("test.wav");
                                        secondMusic.play();
                                }
                        }
                }

                window.clear();
                window.draw(shape);
                window.display();
        }

        return 0;
}
 

If you stick a break point on the first and second music declarations, and make sure your sound playback device is disabled when the first one is executed, then enabled when the second is executed, you'll see the sound will never play. Ideally it would be good if it could check the status of the device at some point (When loading a sound/music? or even when playing them?) and try to open it again if it failed. I've had a look through the changes and I think it might have been something in this commit where the global device was changed:

https://github.com/SFML/SFML/commit/0ad401cc97e5577f594066d3c993daca803572e8


I tested the same thing using SFML 2.1 and as far as I can tell the behavior's the same

But I'm no expert so I'm hoping someone here might know a bit more.

Thanks!

Edit: This is happening on some released games (on a very specific platform) which is why I'm asking (I can see how it would seem a strange request otherwise!) where every few dozen start ups the sound device fails for an unknown reason, but it's usually available again straight after, however the sound will never return until the game has been closed and opened again.
« Last Edit: November 03, 2015, 01:03:06 pm by Jonny »

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Re-check if sound device becomes available after failing
« Reply #1 on: November 03, 2015, 07:15:33 pm »
SFML should have output some warning messages to the console. Can you paste them here?
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Jonny

  • Full Member
  • ***
  • Posts: 114
    • View Profile
    • Email
Re: Re-check if sound device becomes available after failing
« Reply #2 on: November 04, 2015, 11:51:42 am »
Sure:

AL lib: (EE) MMDevApiOpenPlayback: Device init failed: 0x80070490
Failed to open the audio device
An internal OpenAL call failed in SoundSource.cpp(37).
Expression:
   alGenSources(1, &m_source)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

An internal OpenAL call failed in SoundSource.cpp(38).
Expression:
   alSourcei(m_source, AL_BUFFER, 0)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

An internal OpenAL call failed in SoundSource.cpp(37).
Expression:
   alGenSources(1, &m_source)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

An internal OpenAL call failed in SoundSource.cpp(38).
Expression:
   alSourcei(m_source, AL_BUFFER, 0)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

An internal OpenAL call failed in SoundStream.cpp(280).
Expression:
   alGenBuffers(BufferCount, m_buffers)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

An internal OpenAL call failed in SoundStream.cpp(435).
Expression:
   alBufferData(buffer, m_format, data.samples, size, m_sampleRate)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

An internal OpenAL call failed in SoundStream.cpp(438).
Expression:
   alSourceQueueBuffers(m_source, 1, &buffer)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

An internal OpenAL call failed in SoundStream.cpp(435).
Expression:
   alBufferData(buffer, m_format, data.samples, size, m_sampleRate)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

An internal OpenAL call failed in SoundStream.cpp(438).
Expression:
   alSourceQueueBuffers(m_source, 1, &buffer)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

An internal OpenAL call failed in SoundStream.cpp(288).
Expression:
   alSourcePlay(m_source)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

An internal OpenAL call failed in SoundSource.cpp(177).
Expression:
   alGetSourcei(m_source, AL_SOURCE_STATE, &status)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

An internal OpenAL call failed in SoundStream.cpp(324).
Expression:
   alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &nbProcessed)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

An internal OpenAL call failed in SoundSource.cpp(177).
Expression:
   alGetSourcei(m_source, AL_SOURCE_STATE, &status)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

An internal OpenAL call failed in SoundStream.cpp(386).
Expression:
   alSourceStop(m_source)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

An internal OpenAL call failed in SoundStream.cpp(465).
Expression:
   alGetSourcei(m_source, AL_BUFFERS_QUEUED, &nbQueued)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

An internal OpenAL call failed in SoundStream.cpp(392).
Expression:
   alSourcei(m_source, AL_BUFFER, 0)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

An internal OpenAL call failed in SoundStream.cpp(393).
Expression:
   alDeleteBuffers(BufferCount, m_buffers)
Error description:
   AL_INVALID_OPERATION
   The specified operation is not allowed in the current state.


 

That comes out if I use the same repro steps as above (disable device for first music declaration, enable for the second, and pressed space bar once)

The first mention of SoundStream.cpp is where space was pressed

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: Re-check if sound device becomes available after failing
« Reply #3 on: November 05, 2015, 10:54:40 am »
Do you use the dynamic OpenAL library shipped with SFML?

What platform do you use, by the way?
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Jonny

  • Full Member
  • ***
  • Posts: 114
    • View Profile
    • Email
Re: Re-check if sound device becomes available after failing
« Reply #4 on: November 05, 2015, 11:55:27 am »
Yep we use the openAL provided with SFML, unchanged. Those logs are from my windows 7 PC, using VS2013. I expect it should be reproducable on most, if not all windows machines. Haven't tested on other platforms though.

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Re-check if sound device becomes available after failing
« Reply #5 on: November 08, 2015, 02:59:05 pm »
So... what exactly is the "feature" that is required here? If the code tries to create a sound resource when the device is unavailable, it will just fail. You can't differentiate between success and failure because constructors don't return anything. I don't think this should be considered an SFML issue. After all, the same can be said about the graphics side of things if, theoretically, the GPU could be activated only after the application was already started. I think the solution to this problem lies "further upstream". The user has to figure out why the sound device is failing and being temporarily unavailable and fix that instead. For almost all other users, this isn't even an issue.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Jonny

  • Full Member
  • ***
  • Posts: 114
    • View Profile
    • Email
Re: Re-check if sound device becomes available after failing
« Reply #6 on: November 09, 2015, 10:21:32 am »
So... what exactly is the "feature" that is required here?

I'll remember to write it up as a bug report next time.

All I was trying to do is bring to your attention some unexpected behaviour. I don't have any issue with it failing if the sound device is available when a sounds created. My issue here is that if the first sound resource fails, then ALL other afterwards will fail, regardless of whether the sound device is available when they are created.

It's very problematic to fix outside of SFML, because as far as my code is aware, the sound device is working fine (even though it clearly isn't) How am I meant to establish if it randomly failed on the first sound instance I created? SFML actually creates temporary devices whenever a new resource is created, and those can succeed, but then it leaves the global sound device in its failed state? Even if I could somehow catch that, how would I then get SFML to re-initialise the device? As far as I can tell I'd have to destroy every sound resource in my game then re-load them all to force the global initialisation to happen again?

If you think this shouldn't be fixed in SFML, then can I request a way is provided of checking the status of the global device, as that information is readily available inside SFML? Along with that, it would be nice to have a way to re-initialise the device after I've established that the device failed, rather than re-creating all my sound resources?

Edit: In case we're misunderstanding each other, can you tell me what you'd expect the code sample above to do, in the event that when firstMusic is declared the device is unavailable, but when secondMusic is declared it's completely fine? should secondMusic make a sound?
« Last Edit: November 09, 2015, 10:39:25 am by Jonny »

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Re-check if sound device becomes available after failing
« Reply #7 on: November 09, 2015, 06:32:30 pm »
The only thing that I can think of that SFML could do is keep trying to initialize the audio device every time an audio object is created until it finally succeeds. This still doesn't take care of the audio objects that were created before though...

The only interface that could expose a method to check if the audio device is currently valid is sf::Listener. That would almost be a hack in my book since the listener doesn't really have anything to do with the audio device. If such a method was available, how would it help you? If you found out that the audio device isn't available, what would your code do? Delay loading audio until it does become available?
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Jonny

  • Full Member
  • ***
  • Posts: 114
    • View Profile
    • Email
Re: Re-check if sound device becomes available after failing
« Reply #8 on: November 09, 2015, 06:52:55 pm »
Delay loading audio until it does become available?

This is basically what we do as a temporary fix for now, along the lines of:

        while (!audioDevice)
                audioDevice = alcOpenDevice(NULL);
 

In the AudioDevice constructor, but it's a pretty awful (yet effective) solution.

If such a method was available, how would it help you? If you found out that the audio device isn't available, what would your code do?

The main issue is that there's no way of knowing if the audio device inside SFML has failed or not. We could manually check the device using some other API I'm sure, but the thing is, the device can be fine, but there can still be no sound playing if it wasn't available when the first sound resource was created.

Knowing whether SFML's audio device has failed or not would be helpful because it can be different from the actual audio device's current state, so if I could see that SFML's device has failed, but the actual device is fine (i.e.  has become available since the first sound resource was created) Then I know I need to re-initialise SFML's audio stuff.

Currently, as far as i can tell I'd need to destroy all the sf::Sound's and sf::Musics in my game and re-create them to do this, so if there was an easier way to re-initiliase the device that would also be mighty helpful



yparghi

  • Newbie
  • *
  • Posts: 24
  • Maker of the adventure game K Station
    • View Profile
    • K Station
Re: Re-check if sound device becomes available after failing
« Reply #9 on: March 29, 2016, 02:07:12 am »
I know this thread is old, but for what it's worth I was in the same boat, so I'm describing the little hack I used.

I'm coding in Windows on a Macbook through Boot Camp, which is an experience full of delightfully wonky little behaviors. Sometimes (maybe 1 out of 5 times, erratically) when I started my game in Visual Studio, the sf::Music would fail to initialize correctly and I'd get OpenAL errors dumped to stderr. The naive checks I tried, like sf::Music::getStatus(), all returned normal values despite the OpenAL errors.

Fortunately I was building SFML from source, so what did I do? I hacked in an "ALErrorHolder" class into the SFML source, had ALCheck.cpp set an error bool there, then checked ALErrorHolder from my own code to decide whether to re-construct my sf::Music instance on the next game loop.

It's ugly, but it works on my Macbook now. I'd need to test it on more computers to feel better, though.

I'd also love to be able to peek at OpenAL errors after ALCheck.cpp swallows them, but then I'm just some user.
K Station: An adventure game of disappearing lives | Out now on Steam! | Twitter @yashparghi