Forum de la communauté SFML

Aide => Audio => Discussion démarrée par: Oliveira le Octobre 20, 2013, 08:52:48 pm

Titre: Utilisation de sf::Music depuis une bibliothèque dynamique personnelle
Posté par: Oliveira le Octobre 20, 2013, 08:52:48 pm
Hello !

J'ai récemment créé une bibliothèque dynamique (sous Visual C++ 2012) utilisant SFML seulement j'ai un problème avec l'audio. L'erreur survient toujours avec sf::Music, rien d'autre. J'ai pas mal cherché mais je n'ai pas trouvé la source de l'erreur, peut être une mauvaise manipulation de ma part...
Je suis parvenu à écrire un code minimal qui reproduit l'erreur : il s'agit d'un simple lecteur de musique.

Premier cas : m_currentMusic est un sf::Music.

Côté DLL :

CMusicPlayer.hpp
#ifndef CMUSICPLAYER_HPP
#define CMUSICPLAYER_HPP

class DLL_API CMusicPlayer
{
        public:

                void Register(const char* pName, const char* pPath);

                void Play(const char* pName);

                static CMusicPlayer& GetInstance();

        private:

                CMusicPlayer();

                ~CMusicPlayer();

        private:

                static CMusicPlayer ms_instance;

                sf::Music m_currentMusic;
                std::map<const char*, const char*> m_musics;

};

#define MusicPlayer CMusicPlayer::GetInstance()

#endif
 

CMusicPlayer.cpp
#include "DLL.hpp"

CMusicPlayer CMusicPlayer::ms_instance;

CMusicPlayer::CMusicPlayer()
{

}

CMusicPlayer::~CMusicPlayer()
{

}

void CMusicPlayer::Register(const char* pName, const char* pPath)
{
        assert(pName && pPath && m_musics.count(pName) <= 0);

        m_musics[pName] = pPath;
}

void CMusicPlayer::Play(const char* pName)
{
        assert(pName && m_musics.count(pName) > 0);

        m_currentMusic.openFromFile(m_musics.find(pName)->second);

        m_currentMusic.play();
}

CMusicPlayer& CMusicPlayer::GetInstance()
{
        return ms_instance;
}
 

Côté client :

main.cpp
int main()
{
         MusicPlayer.Register("super_musique", "ambiance.ogg");

        MusicPlayer.Play("super_musique");

        return EXIT_SUCCESS;
}
 

Dans ce premier cas, le problème se situe au démarrage de l'application. Il n'y a pas d'erreur mais le thread est bloqué dans le constructeur de CMusicPlayer. Je n'ai pas beaucoup d'information là dessus si ce n'est que l’exécution est coincée dans dsound.dll d'après le débogueur.

Deuxième cas : m_currentMusic devient un pointeur sur sf::Music

Côté DLL :

CMusicPlayer.hpp
#ifndef CMUSICPLAYER_HPP
#define CMUSICPLAYER_HPP

class DLL_API CMusicPlayer
{
        public:

                void Register(const char* pName, const char* pPath);

                void Play(const char* pName);

                static CMusicPlayer& GetInstance();

        private:

                CMusicPlayer();

                ~CMusicPlayer();

        private:

                static CMusicPlayer ms_instance;

                sf::Music* m_currentMusic;
                std::map<const char*, const char*> m_musics;

};

#define MusicPlayer CMusicPlayer::GetInstance()

#endif
 

CMusicPlayer.cpp
#include "DLL.hpp"

CMusicPlayer CMusicPlayer::ms_instance;

CMusicPlayer::CMusicPlayer()
        : m_currentMusic(nullptr)
{

}

CMusicPlayer::~CMusicPlayer()
{
        if (m_currentMusic)
        {
                delete m_currentMusic;
                m_currentMusic = nullptr;
        }
}

void CMusicPlayer::Register(const char* pName, const char* pPath)
{
        assert(pName && pPath && m_musics.count(pName) <= 0);

        m_musics[pName] = pPath;
}

void CMusicPlayer::Play(const char* pName)
{
        assert(pName && m_musics.count(pName) > 0);

        if (m_currentMusic)
        {
                delete m_currentMusic;
                m_currentMusic = nullptr;
        }

        m_currentMusic = new sf::Music;

        m_currentMusic->openFromFile(m_musics.find(pName)->second);

        m_currentMusic->play();
}

CMusicPlayer& CMusicPlayer::GetInstance()
{
        return ms_instance;
}
 

Côté client le main.cpp reste inchangé.

Dans ce deuxième cas, le problème survient à la fermeture de l'application (la musique fonctionne parfaitement). Je reçois le message d'erreur suivant lors du delete de m_currentMusic dans le destructeur de CMusicPlayer :
"an internal OpenAL call failed in SoundSource.cpp <64> : AN_INVALID_OPERATION the specified operation is not allowed in the current state."

Voilà, désolé de la grosse tartine, j'ai essayé d'être le plus clair et précis possible.

Merci d'avance,

Oliveira
Titre: Re : Utilisation de sf::Music depuis une bibliothèque dynamique personnelle
Posté par: Laurent le Octobre 21, 2013, 07:59:22 am
Est-ce que la même chose fonctionne si ta classe est intégrée directement au programme plutôt qu'utilisée à travers une bibliothèque ?
Titre: Re : Utilisation de sf::Music depuis une bibliothèque dynamique personnelle
Posté par: Oliveira le Octobre 21, 2013, 12:55:26 pm
Hello !  :)

Si la classe est directement intégrée au programme, l'application marche parfaitement, que ça soit avec ou sans pointeur pour le sf::Music.
Titre: Re : Utilisation de sf::Music depuis une bibliothèque dynamique personnelle
Posté par: Laurent le Octobre 21, 2013, 01:10:15 pm
Ta bibliothèque lie SFML statiquement ou dynamiquement ? Est-ce que ton programme est aussi lié à SFML directement ?
Titre: Re : Utilisation de sf::Music depuis une bibliothèque dynamique personnelle
Posté par: Oliveira le Octobre 21, 2013, 01:45:56 pm
Ma bibliothèque lie SFML dynamiquement, de même pour mon programme.
Titre: Re : Utilisation de sf::Music depuis une bibliothèque dynamique personnelle
Posté par: Laurent le Octobre 21, 2013, 02:08:55 pm
Donc tu as deux instances de SFML utilisées par ton programme final : l'une dans la DLL, l'autre dans ton exécutable. Ce qui provoque inmanquablement ce genre de problème. Tu n'as donc pas le choix : il faut lier SFML dynamiquement pour qu'elle ne soit physiquement présente qu'à un seul endroit.
Titre: Re : Utilisation de sf::Music depuis une bibliothèque dynamique personnelle
Posté par: Oliveira le Octobre 21, 2013, 02:21:44 pm
Ah oui d'accord je comprends maintenant, voilà bien une erreur de débutant...

Du coup, si je garde le lien dynamique de SFML dans ma bibliothèque et pas côté client, comment je fais pour ne pas avoir d'erreur de symbole externe non résolu dans mon programme client si je ne peux pas mettre sfml-audio-d.lib;...etc dans les dépendances ?

Ou lier uniquement statiquement SFML dans la DLL ?

En gros, c'est quoi la manière la plus naturelle de faire, j'avoue c'est la première fois que je rencontre ce genre de problème.