diff options
| author | manuel <manuel@mausz.at> | 2011-05-10 22:28:58 +0200 |
|---|---|---|
| committer | manuel <manuel@mausz.at> | 2011-05-10 22:28:58 +0200 |
| commit | 1a6c940ed9d7f6136da0e13148314072665342c5 (patch) | |
| tree | 467b259d966ea1ddf9f66440066f57cf3eed68c4 /pacman-c++/common/audio.cpp | |
| parent | cc1bb779661217171418adb0ddbd1ce01815463b (diff) | |
| download | foop-1a6c940ed9d7f6136da0e13148314072665342c5.tar.gz foop-1a6c940ed9d7f6136da0e13148314072665342c5.tar.bz2 foop-1a6c940ed9d7f6136da0e13148314072665342c5.zip | |
- 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
Diffstat (limited to 'pacman-c++/common/audio.cpp')
| -rw-r--r-- | pacman-c++/common/audio.cpp | 262 |
1 files changed, 133 insertions, 129 deletions
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 @@ | |||
| 1 | #include "audio.h" | 1 | #include "audio.h" |
| 2 | #include "constants.h" | 2 | #include "constants.h" |
| 3 | #include <phonon/AudioOutput> | ||
| 4 | #include <QCoreApplication> | 3 | #include <QCoreApplication> |
| 5 | #include <QTimer> | 4 | #include <QTimer> |
| 6 | #include <QFile> | 5 | #include <QFile> |
| 7 | #include <QDir> | 6 | #include <QDir> |
| 8 | #include <QDebug> | 7 | #include <QDebug> |
| 8 | #include <QLibrary> | ||
| 9 | #include <QPluginLoader> | ||
| 9 | 10 | ||
| 10 | /* the universe's only audio manager */ | 11 | /* the universe's only audio manager */ |
| 11 | AudioManager *AudioManager::m_instance = NULL; | 12 | AudioManager *AudioManager::m_instance = NULL; |
| @@ -17,16 +18,22 @@ AudioManager::AudioManager() | |||
| 17 | if (Constants::server) | 18 | if (Constants::server) |
| 18 | { | 19 | { |
| 19 | qDebug() << "Server has no sound"; | 20 | qDebug() << "Server has no sound"; |
| 20 | m_players.append(new AudioPlayer(this)); | 21 | m_players.append(new FakeAudioPlayer(this)); |
| 22 | return; | ||
| 21 | } | 23 | } |
| 22 | else | 24 | |
| 25 | preload(); | ||
| 26 | if (!tryLoadPhononPlugin()) | ||
| 23 | { | 27 | { |
| 24 | preload(); | 28 | qWarning() << "Unable to load audio plugin. Audio disabled.."; |
| 25 | AudioPlayer *firstplayer = new AudioPlayer(this); | 29 | m_players.append(new NoopAudioPlayer(this)); |
| 26 | firstplayer->test(m_sounds[Sound::WakaWaka]); | 30 | return; |
| 27 | m_working = firstplayer->m_working; | ||
| 28 | m_players.append(firstplayer); | ||
| 29 | } | 31 | } |
| 32 | |||
| 33 | AudioPlayer *firstplayer = m_factory->create(this); | ||
| 34 | firstplayer->test(m_sounds[Sound::EatingFruit], Sound::length[Sound::EatingFruit] * 2); | ||
| 35 | m_working = firstplayer->isWorking(); | ||
| 36 | m_players.append(firstplayer); | ||
| 30 | m_muted = false; | 37 | m_muted = false; |
| 31 | } | 38 | } |
| 32 | 39 | ||
| @@ -37,7 +44,7 @@ AudioManager *AudioManager::self() | |||
| 37 | return m_instance; | 44 | return m_instance; |
| 38 | } | 45 | } |
| 39 | 46 | ||
| 40 | bool AudioManager::isWorking() const | 47 | bool AudioManager::isWorking() |
| 41 | { | 48 | { |
| 42 | return m_working; | 49 | return m_working; |
| 43 | } | 50 | } |
| @@ -98,18 +105,6 @@ AudioPlayer *AudioManager::audioPlayer() | |||
| 98 | return m_players.at(0); | 105 | return m_players.at(0); |
| 99 | } | 106 | } |
| 100 | 107 | ||
| 101 | void AudioManager::play(Sound::Type sound, bool wait) | ||
| 102 | { | ||
| 103 | audioPlayer()->play(sound, wait); | ||
| 104 | } | ||
| 105 | |||
| 106 | void AudioManager::enqueue(Sound::Type sound) | ||
| 107 | { | ||
| 108 | if (!isWorking()) | ||
| 109 | return; | ||
| 110 | audioPlayer()->enqueue(Phonon::MediaSource(m_sounds[sound])); | ||
| 111 | } | ||
| 112 | |||
| 113 | void AudioManager::registerAudioPlayer(AudioPlayer *player) | 108 | void AudioManager::registerAudioPlayer(AudioPlayer *player) |
| 114 | { | 109 | { |
| 115 | player->setMuted(m_muted); | 110 | player->setMuted(m_muted); |
| @@ -123,6 +118,13 @@ void AudioManager::unregisterAudioPlayer(AudioPlayer *player) | |||
| 123 | m_players.removeAll(player); | 118 | m_players.removeAll(player); |
| 124 | } | 119 | } |
| 125 | 120 | ||
| 121 | QFile *AudioManager::sound(Sound::Type sound) | ||
| 122 | { | ||
| 123 | if (!isWorking()) | ||
| 124 | return NULL; | ||
| 125 | return m_sounds.at(sound); | ||
| 126 | } | ||
| 127 | |||
| 126 | void AudioManager::unregisterAudioPlayer_helper(QObject *player) | 128 | void AudioManager::unregisterAudioPlayer_helper(QObject *player) |
| 127 | { | 129 | { |
| 128 | unregisterAudioPlayer(static_cast<AudioPlayer *>(player)); | 130 | unregisterAudioPlayer(static_cast<AudioPlayer *>(player)); |
| @@ -132,141 +134,160 @@ void AudioManager::preload() | |||
| 132 | { | 134 | { |
| 133 | m_sounds.clear(); | 135 | m_sounds.clear(); |
| 134 | QDir sounds(":/sound"); | 136 | QDir sounds(":/sound"); |
| 137 | Q_ASSERT(sounds.count() > 0); | ||
| 135 | for(unsigned i = 1; i <= sounds.count(); ++i) | 138 | for(unsigned i = 1; i <= sounds.count(); ++i) |
| 136 | m_sounds.append(new QFile(QString(":/sound/sound%1").arg(i), this)); | 139 | m_sounds.append(new QFile(QString(":/sound/sound%1").arg(i), this)); |
| 137 | } | 140 | } |
| 138 | 141 | ||
| 139 | QFile *AudioManager::sound(Sound::Type sound) | 142 | bool AudioManager::tryLoadPhononPlugin() |
| 140 | { | 143 | { |
| 141 | if (!isWorking()) | 144 | QDir dir = qApp->applicationDirPath(); |
| 145 | QStringList filters; | ||
| 146 | filters << "*phononplayer*"; | ||
| 147 | foreach (QString file, dir.entryList(filters, QDir::Files)) | ||
| 148 | { | ||
| 149 | file = dir.absoluteFilePath(file); | ||
| 150 | if (!QLibrary::isLibrary(file)) | ||
| 151 | continue; | ||
| 152 | QPluginLoader pluginloader(file); | ||
| 153 | if (pluginloader.load()) | ||
| 154 | { | ||
| 155 | qDebug() << "Audio plugin loaded" << file; | ||
| 156 | QObject *plugin = pluginloader.instance(); | ||
| 157 | m_factory = qobject_cast<AudioPlayerFactory *>(plugin); | ||
| 158 | if (m_factory != NULL) | ||
| 159 | return true; | ||
| 160 | } | ||
| 161 | qDebug() << "Unable to load audio plugin:" << file << pluginloader.errorString(); | ||
| 162 | } | ||
| 163 | return false; | ||
| 164 | } | ||
| 165 | |||
| 166 | AudioPlayer *AudioManager::createAudioPlayer() | ||
| 167 | { | ||
| 168 | if (m_factory == NULL) | ||
| 142 | return NULL; | 169 | return NULL; |
| 143 | return m_sounds.at(sound); | 170 | |
| 171 | AudioPlayer *player = m_factory->create(this); | ||
| 172 | registerAudioPlayer(player); | ||
| 173 | return player; | ||
| 144 | } | 174 | } |
| 145 | 175 | ||
| 146 | /* --------------------------------------------------------------- */ | 176 | /* --------------------------------------------------------------- */ |
| 147 | 177 | ||
| 148 | AudioPlayer::AudioPlayer(QObject *parent) | 178 | AudioPlayer *NoopAudioPlayerFactory::create(QObject *parent) |
| 149 | : Phonon::MediaObject(parent), m_working(false) | ||
| 150 | { | 179 | { |
| 151 | if (!Constants::server) | 180 | return new FakeAudioPlayer(parent); |
| 152 | { | ||
| 153 | m_working = AudioManager::m_working; | ||
| 154 | m_output = new Phonon::AudioOutput(Phonon::MusicCategory, this); | ||
| 155 | Phonon::createPath(this, m_output); | ||
| 156 | } | ||
| 157 | } | 181 | } |
| 158 | 182 | ||
| 159 | bool AudioPlayer::isWorking() const | 183 | /* --------------------------------------------------------------- */ |
| 184 | |||
| 185 | NoopAudioPlayer::NoopAudioPlayer(QObject *parent) | ||
| 186 | : AudioPlayer(parent), m_working(false), m_muted(false), m_playing(false), m_paused(false) | ||
| 187 | {} | ||
| 188 | |||
| 189 | bool NoopAudioPlayer::isWorking() const | ||
| 160 | { | 190 | { |
| 161 | return m_working; | 191 | return m_working; |
| 162 | } | 192 | } |
| 163 | 193 | ||
| 164 | void AudioPlayer::setMuted(bool mute) | 194 | void NoopAudioPlayer::setMuted(bool mute) |
| 165 | { | 195 | { |
| 166 | m_output->setMuted(mute); | 196 | m_muted = mute; |
| 167 | } | 197 | } |
| 168 | 198 | ||
| 169 | bool AudioPlayer::isMuted() const | 199 | bool NoopAudioPlayer::isMuted() const |
| 170 | { | 200 | { |
| 171 | return m_output->isMuted(); | 201 | return m_muted; |
| 172 | } | 202 | } |
| 173 | 203 | ||
| 174 | void AudioPlayer::setLoop(QFile *sound) | 204 | void NoopAudioPlayer::play() |
| 175 | { | 205 | { |
| 176 | if (!isWorking()) | 206 | m_playing = true; |
| 177 | return; | 207 | m_paused = false; |
| 178 | 208 | emit finished(); | |
| 179 | if (sound == NULL) | 209 | m_playing = false; |
| 180 | { | 210 | } |
| 181 | disconnect(this, SIGNAL(aboutToFinish()), this, SLOT(loopEnqueue())); | ||
| 182 | return; | ||
| 183 | } | ||
| 184 | 211 | ||
| 185 | m_loopsound = sound; | 212 | void NoopAudioPlayer::play(Sound::Type /* sound */) |
| 186 | connect(this, SIGNAL(aboutToFinish()), this, SLOT(loopEnqueue())); | 213 | { |
| 187 | setCurrentSource(Phonon::MediaSource(m_loopsound)); | 214 | play(); |
| 188 | enqueue(Phonon::MediaSource(m_loopsound)); | ||
| 189 | } | 215 | } |
| 190 | 216 | ||
| 191 | void AudioPlayer::setLoop(Sound::Type sound) | 217 | bool NoopAudioPlayer::isPlaying() |
| 192 | { | 218 | { |
| 193 | setLoop(AudioManager::self()->sound(sound)); | 219 | return m_playing; |
| 194 | } | 220 | } |
| 195 | 221 | ||
| 196 | void AudioPlayer::play() | 222 | void NoopAudioPlayer::enqueue(Sound::Type /* sound */) |
| 223 | {} | ||
| 224 | |||
| 225 | void NoopAudioPlayer::pause() | ||
| 197 | { | 226 | { |
| 198 | Phonon::MediaObject::play(); | 227 | m_paused = true; |
| 228 | m_playing = false; | ||
| 199 | } | 229 | } |
| 200 | 230 | ||
| 201 | void AudioPlayer::play(Sound::Type sound, bool wait) | 231 | bool NoopAudioPlayer::isPaused() |
| 202 | { | 232 | { |
| 203 | if (m_working) | 233 | return m_paused; |
| 204 | { | ||
| 205 | setCurrentSource(Phonon::MediaSource(AudioManager::self()->sound(sound))); | ||
| 206 | play(); | ||
| 207 | } | ||
| 208 | else if (wait) | ||
| 209 | { | ||
| 210 | QTimer *timer = new QTimer(this); | ||
| 211 | timer->setSingleShot(true); | ||
| 212 | unsigned int interval = Sound::length[sound]; | ||
| 213 | /* add a small delay server side only */ | ||
| 214 | if (Constants::server) | ||
| 215 | interval += Constants::tick; | ||
| 216 | timer->setInterval(interval); | ||
| 217 | connect(timer, SIGNAL(timeout()), this, SLOT(finished_ex())); | ||
| 218 | timer->start(); | ||
| 219 | } | ||
| 220 | } | 234 | } |
| 221 | 235 | ||
| 222 | /* this is a simple hack to check if phonon can actually play sounds.. */ | 236 | void NoopAudioPlayer::stop() |
| 223 | void AudioPlayer::test(QFile *testsound) | ||
| 224 | { | 237 | { |
| 225 | stop(); | 238 | m_paused = false; |
| 226 | m_output->setVolume(0); | 239 | m_playing = false; |
| 227 | setCurrentSource(Phonon::MediaSource(testsound)); | 240 | } |
| 228 | connect(this, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(stateChanged_ex(Phonon::State,Phonon::State))); | ||
| 229 | play(); | ||
| 230 | 241 | ||
| 231 | QTimer timer; | 242 | bool NoopAudioPlayer::isStopped() |
| 232 | timer.setSingleShot(true); | 243 | { |
| 233 | connect(&timer, SIGNAL(timeout()), this, SLOT(testFinished())); | 244 | return !m_playing && !m_paused; |
| 234 | timer.start(500); | ||
| 235 | while(timer.isActive()) | ||
| 236 | { | ||
| 237 | qApp->processEvents(); | ||
| 238 | Sleeper::msleep(1); | ||
| 239 | } | ||
| 240 | clear(); | ||
| 241 | } | 245 | } |
| 242 | 246 | ||
| 243 | void AudioPlayer::finished_ex() | 247 | void NoopAudioPlayer::clear() |
| 248 | {} | ||
| 249 | |||
| 250 | void NoopAudioPlayer::clearQueue() | ||
| 251 | {} | ||
| 252 | |||
| 253 | void NoopAudioPlayer::setPrefinishMark(qint32 /* msecToEnd */) | ||
| 254 | {} | ||
| 255 | |||
| 256 | void NoopAudioPlayer::prefinishMarkReached_ex(qint32 mark) | ||
| 244 | { | 257 | { |
| 245 | emit finished(); | 258 | emit prefinishMarkReached(mark); |
| 246 | } | 259 | } |
| 247 | 260 | ||
| 248 | void AudioPlayer::stateChanged_ex(Phonon::State newstate, Phonon::State /* oldstate */) | 261 | void NoopAudioPlayer::test(QFile * /* testsound */, qint32 /* length */) |
| 262 | {} | ||
| 263 | |||
| 264 | /* --------------------------------------------------------------- */ | ||
| 265 | |||
| 266 | FakeAudioPlayer::FakeAudioPlayer(QObject *parent) | ||
| 267 | : NoopAudioPlayer(parent) | ||
| 249 | { | 268 | { |
| 250 | if (newstate != Phonon::ErrorState) | 269 | m_working = true; |
| 251 | { | 270 | connect(&m_timer, SIGNAL(timeout()), this, SLOT(finished_ex())); |
| 252 | m_working = true; | ||
| 253 | m_output->setVolume(1); | ||
| 254 | qDebug() << "Sound is working for you!"; | ||
| 255 | } | ||
| 256 | disconnect(this, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged_ex(Phonon::State, Phonon::State))); | ||
| 257 | stop(); | ||
| 258 | } | 271 | } |
| 259 | 272 | ||
| 260 | void AudioPlayer::testFinished() | 273 | void FakeAudioPlayer::play(Sound::Type sound) |
| 261 | { | 274 | { |
| 262 | if (!m_working) | 275 | m_playing = true; |
| 263 | qWarning() << "There's no sound for you :("; | 276 | m_paused = false; |
| 264 | disconnect(this, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged_ex(Phonon::State, Phonon::State))); | 277 | |
| 278 | m_timer.setSingleShot(true); | ||
| 279 | unsigned int interval = Sound::length[sound]; | ||
| 280 | /* add a small delay server side only */ | ||
| 281 | if (Constants::server) | ||
| 282 | interval += Constants::tick; | ||
| 283 | m_timer.setInterval(interval); | ||
| 284 | m_timer.start(); | ||
| 265 | } | 285 | } |
| 266 | 286 | ||
| 267 | void AudioPlayer::loopEnqueue() | 287 | void FakeAudioPlayer::finished_ex() |
| 268 | { | 288 | { |
| 269 | enqueue(Phonon::MediaSource(m_loopsound)); | 289 | m_playing = false; |
| 290 | emit finished(); | ||
| 270 | } | 291 | } |
| 271 | 292 | ||
| 272 | /* --------------------------------------------------------------- */ | 293 | /* --------------------------------------------------------------- */ |
| @@ -274,12 +295,12 @@ void AudioPlayer::loopEnqueue() | |||
| 274 | GaplessAudioPlayer::GaplessAudioPlayer(Sound::Type sound, qint32 mark, QObject *parent) | 295 | GaplessAudioPlayer::GaplessAudioPlayer(Sound::Type sound, qint32 mark, QObject *parent) |
| 275 | : QObject(parent), m_sound(sound) | 296 | : QObject(parent), m_sound(sound) |
| 276 | { | 297 | { |
| 277 | m_working = AudioManager::m_working; | 298 | m_working = AudioManager::isWorking(); |
| 278 | if (!m_working) | 299 | if (!m_working) |
| 279 | return; | 300 | return; |
| 280 | 301 | ||
| 281 | m_player1 = new AudioPlayer(this); | 302 | m_player1 = AudioManager::self()->createAudioPlayer(); |
| 282 | m_player2 = new AudioPlayer(this); | 303 | m_player2 = AudioManager::self()->createAudioPlayer(); |
| 283 | 304 | ||
| 284 | m_player2->setPrefinishMark(mark); | 305 | m_player2->setPrefinishMark(mark); |
| 285 | m_player1->setPrefinishMark(mark); | 306 | m_player1->setPrefinishMark(mark); |
| @@ -313,7 +334,7 @@ void GaplessAudioPlayer::play() | |||
| 313 | { | 334 | { |
| 314 | if (!m_working) | 335 | if (!m_working) |
| 315 | return; | 336 | return; |
| 316 | if (m_player1->state() != Phonon::PlayingState && m_player2->state() != Phonon::PlayingState) | 337 | if (!m_player1->isPlaying() && !m_player2->isPlaying()) |
| 317 | startPlayer1(); | 338 | startPlayer1(); |
| 318 | } | 339 | } |
| 319 | 340 | ||
| @@ -321,9 +342,9 @@ void GaplessAudioPlayer::pause() | |||
| 321 | { | 342 | { |
| 322 | if (!m_working) | 343 | if (!m_working) |
| 323 | return; | 344 | return; |
| 324 | if (m_player1->state() != Phonon::PausedState) | 345 | if (!m_player1->isPaused()) |
| 325 | m_player1->pause(); | 346 | m_player1->pause(); |
| 326 | if (m_player2->state() != Phonon::PausedState) | 347 | if (!m_player2->isPaused()) |
| 327 | m_player2->pause(); | 348 | m_player2->pause(); |
| 328 | } | 349 | } |
| 329 | 350 | ||
| @@ -336,20 +357,3 @@ void GaplessAudioPlayer::startPlayer2() | |||
| 336 | { | 357 | { |
| 337 | m_player2->play(m_sound); | 358 | m_player2->play(m_sound); |
| 338 | } | 359 | } |
| 339 | |||
| 340 | /* --------------------------------------------------------------- */ | ||
| 341 | |||
| 342 | void AudioPlayer::Sleeper::sleep(unsigned long secs) | ||
| 343 | { | ||
| 344 | QThread::sleep(secs); | ||
| 345 | } | ||
| 346 | |||
| 347 | void AudioPlayer::Sleeper::msleep(unsigned long msecs) | ||
| 348 | { | ||
| 349 | QThread::msleep(msecs); | ||
| 350 | } | ||
| 351 | |||
| 352 | void AudioPlayer::Sleeper::usleep(unsigned long usecs) | ||
| 353 | { | ||
| 354 | QThread::usleep(usecs); | ||
| 355 | } | ||
