As already said on GitHub, I don't consider that one a stream-specific issue; the same applies to files and memory buffers.
The way how SFML currently loads resources, through
bool Resource::loadFromXy() member functions, is not ideal from several standpoints. Error handling is one, but more important in my opinion is that the library is not really clear about reusing the instance (as you say). It is not obvious if
loadFromXy() can be applied multiple times, and if so, whether it truly resets the state of the whole instance.
If I had to design a new API for SFML 3, I would use the named constructor idiom combined with move semantics:
sf::Music music; // empty
music = sf::Music::fromFile("music.ogg"); // construction + move
...
music = sf::Music::fromStream(stream); // reuse instance
...
music = sf::Music(); // early destruction
As you see, this kind of code makes it obvious that the whole instance is reassigned. Plus, features like explicit resource release (last line) effectively come for free.
I think the
pause() issue mentioned in this thread is not directly related to the loading/lifetime issues.
The underlying problem is that
pause() and
play() are asynchronous operations, while
stop() is synchronous. The difference between
pause() and
stop() is rather subtle -- from a user point of view, the former maintains the playing offset while the latter resets it to the beginning. Other things, like the fact that the thread is destroyed in
stop(), are rather implementation details. The documentation states almost nothing about the threading behavior, so one really has to check the code in order to see what happens.
The problem with asynchronous operations is that they add certain complexity. Things are running concurrently, and with the current API there's no good way to be notified when they're finished (only the spinlock workaround I mentioned). I think the reason why
stop() is synchronous is defined behavior on destruction: when the music is destroyed while still playing, it has to wait for the streaming thread to finish reading before it can safely deallocate its resources.
I assume the reason why
pause() is
not synchronous is to avoid blocking the main thread. And in most cases, this is just fine, like
play() it can run in the background. But there are advanced use cases like mine where this doesn't work, and if the implementation stays as is, the behavior should at least be clearly documented. Just because most users happily work with separate files, this doesn't mean we can always assume that.