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

Author Topic: sf::Music play() and pause() bug?  (Read 6634 times)

0 Members and 1 Guest are viewing this topic.

Ceylo

  • Hero Member
  • *****
  • Posts: 2325
    • View Profile
    • http://sfemovie.yalir.org/
    • Email
sf::Music play() and pause() bug?
« on: December 25, 2014, 10:52:56 pm »
Hello,

Just encountered an issue that I reproduced with this sample code:

#include <SFML/Audio.hpp>
#include <cassert>
#include "ResourcePath.hpp"

int main(int, char const**)
{
    sf::Music music;
    if (!music.openFromFile(resourcePath() + "nice_music.ogg")) {
        return EXIT_FAILURE;
    }
   
    music.play();
   
    sf::sleep(sf::seconds(2));
   
    while (true)
    {
        assert(music.getStatus() == sf::Music::Playing);    // (1)
        music.pause();
        assert(music.getStatus() == sf::Music::Paused);     // (2)
        music.play();
        assert(music.getStatus() == sf::Music::Playing);    // (3)
    }

    return EXIT_SUCCESS;
}
 

This code crashes most of the time on the assert (3), sometimes on the (2), and even some times on the (1) !!! I'm using the latest sources from Git (freshly built right now) on OS X 10.10.

I thought pause() and play() would be synchronous but… is this expected? ;D
Want to play movies in your SFML application? Check out sfeMovie!

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: sf::Music play() and pause() bug?
« Reply #1 on: December 25, 2014, 11:00:33 pm »
I guess it's related to https://github.com/SFML/SFML/pull/754.
Laurent Gomila - SFML developer

Ceylo

  • Hero Member
  • *****
  • Posts: 2325
    • View Profile
    • http://sfemovie.yalir.org/
    • Email
Re: sf::Music play() and pause() bug?
« Reply #2 on: December 25, 2014, 11:12:46 pm »
I'd read this topic but… there the issue looks to be getStatus() taking too long, but not giving inaccurate result. Did I miss something?

I also tried binary1248 soundstream_contention branch where he has done some changes but it doesn't fix the current assertion failure.
Want to play movies in your SFML application? Check out sfeMovie!

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: sf::Music play() and pause() bug?
« Reply #3 on: December 26, 2014, 12:04:09 am »
The intent of that pull request is the exact opposite of what you are experiencing. For some users who request the status right after e.g. playing, it just took too long for SFML to return any result (they did not care what it was, just that it returned fast).

This behaviour (asynchronous requests to do something) is how OpenAL does stuff. SFML doesn't try to pretend it is any other way. Even if SFML did block until OpenAL returned some useful status result, it is not guaranteed that it will reflect what is really happening. If you are superhuman, you might be able to notice in some cases that the audio keeps playing a few more milliseconds even though OpenAL said that the stream was paused. This is how audio streaming works in general, from a software and definitely a hardware perspective.

The real question now is: Why do you want pause() and play() to be synchronous? ;) If you were really desperate to make it happen, you could just busy wait out those milliseconds/microseconds and you will be sure that the returned status will be correct. If you ask me, humans can't perceive delays on the order of a few milliseconds anyway, and not having getStatus() block for 80ms or more has a higher priority.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: sf::Music play() and pause() bug?
« Reply #4 on: December 26, 2014, 01:19:29 am »
Could we add a note about that to the tutorials and documentation?  This makes perfect sense to me after your explanation but it's definitely not what I would have expected.  Maybe something like "Because OpenAL is an asynchronous API, this function may return an out of date value if the status changed in the last several milliseconds".  Or is it more like "may appear to ... because play()/pause() are async"?

Also, is getStatus() the only function affected by this?  Or can getVolume/getPitch/getPlayingOffset/etc also potentially return an out of date value if called just after the corresponding setter/mutator?

Ceylo

  • Hero Member
  • *****
  • Posts: 2325
    • View Profile
    • http://sfemovie.yalir.org/
    • Email
Re: sf::Music play() and pause() bug?
« Reply #5 on: December 26, 2014, 01:37:58 am »
As Ixrec points out, the whole point is that this behaviour was not expected. Although when you explain why it happens it makes sense.

This also look specific to be implementation detail, although the end-user doesn't really care if SFML uses OpenAL (which is asynchronous and operation queue-oriented) or something else (which could be fully synchronous and block the execution until the wanted state is reached). This is just so weird to find out that the music is still playing even if stop was requested! :D (at least from the program execution pipeline point of view)

Even if the reality of the sound produced by the hardware would say that there is still sound coming out, I would expect the state of the SoundStream to reflect the request (as long as you can guarantee that reality will catch up with the software state).

As for the constraint on my side, there isn't really any. I just had a sanity check in my code to make sure the stream was not playing while I was doing some operations on the data that would be fed to the SoundStream. The point being that I don't want SFML to fetch data while I'm doing these operations. Here it looks like I can either wait a bit or not care about the result of the sanity check (but I like sanity checks :( ).

P.S.: thanks for all the work on SFML :)
Want to play movies in your SFML application? Check out sfeMovie!

Ceylo

  • Hero Member
  • *****
  • Posts: 2325
    • View Profile
    • http://sfemovie.yalir.org/
    • Email
Re: sf::Music play() and pause() bug?
« Reply #6 on: January 04, 2015, 09:36:59 pm »
I've applied the wait-while-status-did-not-change strategy to get consistent status from sf::SoundStream. However even with this busy wait I get issues on Linux at least (not on OS X, and untested on Windows):
#include <SFML/Audio.hpp>
#include <cassert>
#include <iostream>

void waitForStatusUpdate(const sf::Music& music, sf::Music::Status expectedStatus)
{
    sf::Clock timeout;
    while (music.getStatus() != expectedStatus && timeout.getElapsedTime() < sf::seconds(5))
        sf::sleep(sf::microseconds(10));

    assert(timeout.getElapsedTime() < sf::seconds(5)); // Audio status did not updated within 5 seconds
    std::cout << "Status " << expectedStatus << " reached" << std::endl;
}

int main()
{
    sf::Music music;

    if (! music.openFromFile("test.wav"))
    {
        std::cout << "could not open file" << std::endl;
        return 1;
    }

    music.play();
    //sf::sleep(sf::seconds(1));

    while (music.getStatus() != sf::Music::Stopped)
    {
        music.play();
        waitForStatusUpdate(music, sf::Music::Playing);
        music.pause();
        waitForStatusUpdate(music, sf::Music::Paused);
    }

    return 0;
}

On OS X this code will continuously print this many times
Code: [Select]
Status 2 reached
Status 1 reached

On Linux though, I only get this:
Code: [Select]
Status 2 reached
a.out: musicTimeout.cpp:12: void waitForStatusUpdate(const sf::Music&, sf::SoundSource::Status): Assertion `timeout.getElapsedTime() < sf::seconds(5)' failed.
Abandon (core dumped)

However if I uncomment the first sleep(), right after the first play(), everything goes fine just like on OS X. So there looks to be a timing/threading issue here.

Did I misunderstand something again or is it just broken here?

Thanks
Want to play movies in your SFML application? Check out sfeMovie!

Ceylo

  • Hero Member
  • *****
  • Posts: 2325
    • View Profile
    • http://sfemovie.yalir.org/
    • Email
Re: sf::Music play() and pause() bug?
« Reply #7 on: January 04, 2015, 10:13:54 pm »
Ok, I just built latest SFML from Git head on Linux and now it works fine :)

So nothing more to say here :D false alarm! Thanks IRC
« Last Edit: January 04, 2015, 10:19:22 pm by Ceylo »
Want to play movies in your SFML application? Check out sfeMovie!

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: sf::Music play() and pause() bug?
« Reply #8 on: January 04, 2015, 10:25:15 pm »
That looks like a good candidate for a regression test, though I'm not sure if the unittest branch is meant to include slightly "fuzzy" tests like this or not.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: sf::Music play() and pause() bug?
« Reply #9 on: January 04, 2015, 10:28:32 pm »
Just wanted to add that it works fine on Windows as well. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/