From 1a6c940ed9d7f6136da0e13148314072665342c5 Mon Sep 17 00:00:00 2001 From: manuel Date: Tue, 10 May 2011 22:28:58 +0200 Subject: - refactorized audio once more: audio is now a plugin which gets loaded at runtime - thus server has no dependency to phonon any more - remove client dependency to qtnetwork - fix enet deinitialization on windows --- pacman-c++/common/actor.cpp | 6 +- pacman-c++/common/actor.h | 2 +- pacman-c++/common/audio.cpp | 262 ++++++++++++++++++++++--------------------- pacman-c++/common/audio.h | 147 +++++++++++++++++------- pacman-c++/common/common.pro | 2 + 5 files changed, 246 insertions(+), 173 deletions(-) (limited to 'pacman-c++/common') diff --git a/pacman-c++/common/actor.cpp b/pacman-c++/common/actor.cpp index de8d77e..83a54e3 100644 --- a/pacman-c++/common/actor.cpp +++ b/pacman-c++/common/actor.cpp @@ -296,21 +296,21 @@ void Actor::die() setZValue(zValue() * 10); m_dieing->start(); if (m_local) - AudioManager::self()->play(Sound::Die); + AudioManager::self()->audioPlayer()->play(Sound::Die); } void Actor::eatingFruit() { if (!m_local) return; - AudioManager::self()->play(Sound::EatingFruit); + AudioManager::self()->audioPlayer()->play(Sound::EatingFruit); } void Actor::eatingPacman() { if (!m_local) return; - AudioManager::self()->play(Sound::EatingGhost); + AudioManager::self()->audioPlayer()->play(Sound::EatingGhost); } void Actor::startEating() diff --git a/pacman-c++/common/actor.h b/pacman-c++/common/actor.h index c30c62a..189afba 100644 --- a/pacman-c++/common/actor.h +++ b/pacman-c++/common/actor.h @@ -11,7 +11,7 @@ class Actor : public GameEntity { -Q_OBJECT + Q_OBJECT public: enum Movement diff --git a/pacman-c++/common/audio.cpp b/pacman-c++/common/audio.cpp index 70cd37e..d29303d 100644 --- a/pacman-c++/common/audio.cpp +++ b/pacman-c++/common/audio.cpp @@ -1,11 +1,12 @@ #include "audio.h" #include "constants.h" -#include #include #include #include #include #include +#include +#include /* the universe's only audio manager */ AudioManager *AudioManager::m_instance = NULL; @@ -17,16 +18,22 @@ AudioManager::AudioManager() if (Constants::server) { qDebug() << "Server has no sound"; - m_players.append(new AudioPlayer(this)); + m_players.append(new FakeAudioPlayer(this)); + return; } - else + + preload(); + if (!tryLoadPhononPlugin()) { - preload(); - AudioPlayer *firstplayer = new AudioPlayer(this); - firstplayer->test(m_sounds[Sound::WakaWaka]); - m_working = firstplayer->m_working; - m_players.append(firstplayer); + qWarning() << "Unable to load audio plugin. Audio disabled.."; + m_players.append(new NoopAudioPlayer(this)); + return; } + + AudioPlayer *firstplayer = m_factory->create(this); + firstplayer->test(m_sounds[Sound::EatingFruit], Sound::length[Sound::EatingFruit] * 2); + m_working = firstplayer->isWorking(); + m_players.append(firstplayer); m_muted = false; } @@ -37,7 +44,7 @@ AudioManager *AudioManager::self() return m_instance; } -bool AudioManager::isWorking() const +bool AudioManager::isWorking() { return m_working; } @@ -98,18 +105,6 @@ AudioPlayer *AudioManager::audioPlayer() return m_players.at(0); } -void AudioManager::play(Sound::Type sound, bool wait) -{ - audioPlayer()->play(sound, wait); -} - -void AudioManager::enqueue(Sound::Type sound) -{ - if (!isWorking()) - return; - audioPlayer()->enqueue(Phonon::MediaSource(m_sounds[sound])); -} - void AudioManager::registerAudioPlayer(AudioPlayer *player) { player->setMuted(m_muted); @@ -123,6 +118,13 @@ void AudioManager::unregisterAudioPlayer(AudioPlayer *player) m_players.removeAll(player); } +QFile *AudioManager::sound(Sound::Type sound) +{ + if (!isWorking()) + return NULL; + return m_sounds.at(sound); +} + void AudioManager::unregisterAudioPlayer_helper(QObject *player) { unregisterAudioPlayer(static_cast(player)); @@ -132,141 +134,160 @@ void AudioManager::preload() { m_sounds.clear(); QDir sounds(":/sound"); + Q_ASSERT(sounds.count() > 0); for(unsigned i = 1; i <= sounds.count(); ++i) m_sounds.append(new QFile(QString(":/sound/sound%1").arg(i), this)); } -QFile *AudioManager::sound(Sound::Type sound) +bool AudioManager::tryLoadPhononPlugin() { - if (!isWorking()) + QDir dir = qApp->applicationDirPath(); + QStringList filters; + filters << "*phononplayer*"; + foreach (QString file, dir.entryList(filters, QDir::Files)) + { + file = dir.absoluteFilePath(file); + if (!QLibrary::isLibrary(file)) + continue; + QPluginLoader pluginloader(file); + if (pluginloader.load()) + { + qDebug() << "Audio plugin loaded" << file; + QObject *plugin = pluginloader.instance(); + m_factory = qobject_cast(plugin); + if (m_factory != NULL) + return true; + } + qDebug() << "Unable to load audio plugin:" << file << pluginloader.errorString(); + } + return false; +} + +AudioPlayer *AudioManager::createAudioPlayer() +{ + if (m_factory == NULL) return NULL; - return m_sounds.at(sound); + + AudioPlayer *player = m_factory->create(this); + registerAudioPlayer(player); + return player; } /* --------------------------------------------------------------- */ -AudioPlayer::AudioPlayer(QObject *parent) - : Phonon::MediaObject(parent), m_working(false) +AudioPlayer *NoopAudioPlayerFactory::create(QObject *parent) { - if (!Constants::server) - { - m_working = AudioManager::m_working; - m_output = new Phonon::AudioOutput(Phonon::MusicCategory, this); - Phonon::createPath(this, m_output); - } + return new FakeAudioPlayer(parent); } -bool AudioPlayer::isWorking() const +/* --------------------------------------------------------------- */ + +NoopAudioPlayer::NoopAudioPlayer(QObject *parent) + : AudioPlayer(parent), m_working(false), m_muted(false), m_playing(false), m_paused(false) +{} + +bool NoopAudioPlayer::isWorking() const { return m_working; } -void AudioPlayer::setMuted(bool mute) +void NoopAudioPlayer::setMuted(bool mute) { - m_output->setMuted(mute); + m_muted = mute; } -bool AudioPlayer::isMuted() const +bool NoopAudioPlayer::isMuted() const { - return m_output->isMuted(); + return m_muted; } -void AudioPlayer::setLoop(QFile *sound) +void NoopAudioPlayer::play() { - if (!isWorking()) - return; - - if (sound == NULL) - { - disconnect(this, SIGNAL(aboutToFinish()), this, SLOT(loopEnqueue())); - return; - } + m_playing = true; + m_paused = false; + emit finished(); + m_playing = false; +} - m_loopsound = sound; - connect(this, SIGNAL(aboutToFinish()), this, SLOT(loopEnqueue())); - setCurrentSource(Phonon::MediaSource(m_loopsound)); - enqueue(Phonon::MediaSource(m_loopsound)); +void NoopAudioPlayer::play(Sound::Type /* sound */) +{ + play(); } -void AudioPlayer::setLoop(Sound::Type sound) +bool NoopAudioPlayer::isPlaying() { - setLoop(AudioManager::self()->sound(sound)); + return m_playing; } -void AudioPlayer::play() +void NoopAudioPlayer::enqueue(Sound::Type /* sound */) +{} + +void NoopAudioPlayer::pause() { - Phonon::MediaObject::play(); + m_paused = true; + m_playing = false; } -void AudioPlayer::play(Sound::Type sound, bool wait) +bool NoopAudioPlayer::isPaused() { - if (m_working) - { - setCurrentSource(Phonon::MediaSource(AudioManager::self()->sound(sound))); - play(); - } - else if (wait) - { - QTimer *timer = new QTimer(this); - timer->setSingleShot(true); - unsigned int interval = Sound::length[sound]; - /* add a small delay server side only */ - if (Constants::server) - interval += Constants::tick; - timer->setInterval(interval); - connect(timer, SIGNAL(timeout()), this, SLOT(finished_ex())); - timer->start(); - } + return m_paused; } -/* this is a simple hack to check if phonon can actually play sounds.. */ -void AudioPlayer::test(QFile *testsound) +void NoopAudioPlayer::stop() { - stop(); - m_output->setVolume(0); - setCurrentSource(Phonon::MediaSource(testsound)); - connect(this, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(stateChanged_ex(Phonon::State,Phonon::State))); - play(); + m_paused = false; + m_playing = false; +} - QTimer timer; - timer.setSingleShot(true); - connect(&timer, SIGNAL(timeout()), this, SLOT(testFinished())); - timer.start(500); - while(timer.isActive()) - { - qApp->processEvents(); - Sleeper::msleep(1); - } - clear(); +bool NoopAudioPlayer::isStopped() +{ + return !m_playing && !m_paused; } -void AudioPlayer::finished_ex() +void NoopAudioPlayer::clear() +{} + +void NoopAudioPlayer::clearQueue() +{} + +void NoopAudioPlayer::setPrefinishMark(qint32 /* msecToEnd */) +{} + +void NoopAudioPlayer::prefinishMarkReached_ex(qint32 mark) { - emit finished(); + emit prefinishMarkReached(mark); } -void AudioPlayer::stateChanged_ex(Phonon::State newstate, Phonon::State /* oldstate */) +void NoopAudioPlayer::test(QFile * /* testsound */, qint32 /* length */) +{} + +/* --------------------------------------------------------------- */ + +FakeAudioPlayer::FakeAudioPlayer(QObject *parent) + : NoopAudioPlayer(parent) { - if (newstate != Phonon::ErrorState) - { - m_working = true; - m_output->setVolume(1); - qDebug() << "Sound is working for you!"; - } - disconnect(this, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged_ex(Phonon::State, Phonon::State))); - stop(); + m_working = true; + connect(&m_timer, SIGNAL(timeout()), this, SLOT(finished_ex())); } -void AudioPlayer::testFinished() +void FakeAudioPlayer::play(Sound::Type sound) { - if (!m_working) - qWarning() << "There's no sound for you :("; - disconnect(this, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged_ex(Phonon::State, Phonon::State))); + m_playing = true; + m_paused = false; + + m_timer.setSingleShot(true); + unsigned int interval = Sound::length[sound]; + /* add a small delay server side only */ + if (Constants::server) + interval += Constants::tick; + m_timer.setInterval(interval); + m_timer.start(); } -void AudioPlayer::loopEnqueue() +void FakeAudioPlayer::finished_ex() { - enqueue(Phonon::MediaSource(m_loopsound)); + m_playing = false; + emit finished(); } /* --------------------------------------------------------------- */ @@ -274,12 +295,12 @@ void AudioPlayer::loopEnqueue() GaplessAudioPlayer::GaplessAudioPlayer(Sound::Type sound, qint32 mark, QObject *parent) : QObject(parent), m_sound(sound) { - m_working = AudioManager::m_working; + m_working = AudioManager::isWorking(); if (!m_working) return; - m_player1 = new AudioPlayer(this); - m_player2 = new AudioPlayer(this); + m_player1 = AudioManager::self()->createAudioPlayer(); + m_player2 = AudioManager::self()->createAudioPlayer(); m_player2->setPrefinishMark(mark); m_player1->setPrefinishMark(mark); @@ -313,7 +334,7 @@ void GaplessAudioPlayer::play() { if (!m_working) return; - if (m_player1->state() != Phonon::PlayingState && m_player2->state() != Phonon::PlayingState) + if (!m_player1->isPlaying() && !m_player2->isPlaying()) startPlayer1(); } @@ -321,9 +342,9 @@ void GaplessAudioPlayer::pause() { if (!m_working) return; - if (m_player1->state() != Phonon::PausedState) + if (!m_player1->isPaused()) m_player1->pause(); - if (m_player2->state() != Phonon::PausedState) + if (!m_player2->isPaused()) m_player2->pause(); } @@ -336,20 +357,3 @@ void GaplessAudioPlayer::startPlayer2() { m_player2->play(m_sound); } - -/* --------------------------------------------------------------- */ - -void AudioPlayer::Sleeper::sleep(unsigned long secs) -{ - QThread::sleep(secs); -} - -void AudioPlayer::Sleeper::msleep(unsigned long msecs) -{ - QThread::msleep(msecs); -} - -void AudioPlayer::Sleeper::usleep(unsigned long usecs) -{ - QThread::usleep(usecs); -} diff --git a/pacman-c++/common/audio.h b/pacman-c++/common/audio.h index 6aec42d..bc7d66e 100644 --- a/pacman-c++/common/audio.h +++ b/pacman-c++/common/audio.h @@ -4,13 +4,7 @@ #include #include #include -#include -#include - -namespace Phonon -{ - class AudioOutput; -} +#include namespace Sound { @@ -32,46 +26,98 @@ namespace Sound /* --------------------------------------------------------------- */ class AudioPlayer - : public Phonon::MediaObject + : public QObject { Q_OBJECT friend class AudioManager; -private: - class Sleeper - : public QThread - { - public: - static void sleep(unsigned long secs); - static void msleep(unsigned long msecs); - static void usleep(unsigned long usecs); - }; +public: + AudioPlayer(QObject *parent = 0) + : QObject(parent) + {} + virtual ~AudioPlayer() + {} + virtual bool isWorking() const = 0; + virtual void setMuted(bool mute = true) = 0; + virtual bool isMuted() const = 0; + virtual void play() = 0; + virtual void play(Sound::Type sound) = 0; + virtual bool isPlaying() = 0; + virtual void enqueue(Sound::Type sound) = 0; + virtual void pause() = 0; + virtual bool isPaused() = 0; + virtual void stop() = 0; + virtual bool isStopped() = 0; + virtual void clear() = 0; + virtual void clearQueue() = 0; + virtual void setPrefinishMark(qint32 msecToEnd) = 0; + +protected slots: + virtual void prefinishMarkReached_ex(qint32 mark) = 0; + +signals: + void finished(); + void prefinishMarkReached(qint32 mark); + +protected: + virtual void test(QFile *testsound, qint32 length) = 0; +}; + +/* --------------------------------------------------------------- */ + +class NoopAudioPlayer + : public AudioPlayer +{ + Q_OBJECT + friend class AudioManager; public: - AudioPlayer(QObject *parent = 0); - bool isWorking() const; - void setMuted(bool mute = true); - bool isMuted() const; - void setLoop(Sound::Type sound); - void play(); - void play(Sound::Type sound, bool wait = false); + NoopAudioPlayer(QObject *parent = 0); + virtual bool isWorking() const; + virtual void setMuted(bool mute = true); + virtual bool isMuted() const; + virtual void play(); + virtual void play(Sound::Type sound); + virtual bool isPlaying(); + virtual void enqueue(Sound::Type sound); + virtual void pause(); + virtual bool isPaused(); + virtual void stop(); + virtual bool isStopped(); + virtual void clear(); + virtual void clearQueue(); + virtual void setPrefinishMark(qint32 msecToEnd); + +protected slots: + virtual void prefinishMarkReached_ex(qint32 mark); protected: - void test(QFile *testsound); - void setLoop(QFile *sound); + virtual void test(QFile *testsound, qint32 length); -public slots: - void loopEnqueue(); +protected: + bool m_working; + bool m_muted; + bool m_playing; + bool m_paused; +}; + +/* --------------------------------------------------------------- */ + +class FakeAudioPlayer + : public NoopAudioPlayer +{ + Q_OBJECT + friend class AudioManager; + +public: + FakeAudioPlayer(QObject *parent = 0); + virtual void play(Sound::Type sound); protected slots: void finished_ex(); - void testFinished(); - void stateChanged_ex(Phonon::State newstate, Phonon::State oldstate); protected: - bool m_working; - QFile *m_loopsound; - Phonon::AudioOutput *m_output; + QTimer m_timer; }; /* --------------------------------------------------------------- */ @@ -102,17 +148,37 @@ protected: /* --------------------------------------------------------------- */ +class AudioPlayerFactory +{ +public: + virtual ~AudioPlayerFactory() + {} + virtual AudioPlayer *create(QObject *parent = 0) = 0; +}; + +Q_DECLARE_INTERFACE(AudioPlayerFactory, "at.ac.tuwien.foop.pacman.AudioPlayerFactory/1.0"); + +/* --------------------------------------------------------------- */ + +class NoopAudioPlayerFactory + : public AudioPlayerFactory +{ +public: + virtual AudioPlayer *create(QObject *parent = 0); +}; + +/* --------------------------------------------------------------- */ + class AudioManager : public QObject { Q_OBJECT - friend class AudioPlayer; friend class GaplessAudioPlayer; public: AudioManager(); static AudioManager *self(); - bool isWorking() const; + static bool isWorking(); void setMuted(bool mute = true); bool isMuted() const; void pause(); @@ -121,21 +187,21 @@ public: void clearQueue() const; AudioPlayer *audioPlayer(); - void play(Sound::Type sound, bool wait = false); - void enqueue(Sound::Type sound); - void registerAudioPlayer(AudioPlayer *player); void unregisterAudioPlayer(AudioPlayer *player); + QFile *sound(Sound::Type sound); + signals: void mutedChanged(bool muted); private slots: void unregisterAudioPlayer_helper(QObject *player); -private: +protected: void preload(); - QFile *sound(Sound::Type sound); + bool tryLoadPhononPlugin(); + AudioPlayer *createAudioPlayer(); private: bool m_muted; @@ -143,6 +209,7 @@ private: static AudioManager *m_instance; QList m_sounds; QList m_players; + AudioPlayerFactory *m_factory; }; #endif // AUDIOPLAYER_H diff --git a/pacman-c++/common/common.pro b/pacman-c++/common/common.pro index ca82382..e7e415e 100644 --- a/pacman-c++/common/common.pro +++ b/pacman-c++/common/common.pro @@ -1,6 +1,8 @@ TEMPLATE = lib CONFIG += staticlib +DEFINES += PACMAN_COMMON + include(../common.pri) SOURCES += pixmapitem.cpp \ -- cgit v1.2.3