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.
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
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