31 #include <QtCore/QBasicTimer>
32 #include <QtCore/QQueue>
33 #include <QtCore/QTimer>
34 #include <QtCore/QTimerEvent>
35 #include <QtCore/QStack>
36 #include <QSignalMapper>
42 #include <kstandarddirs.h>
43 #include <kconfiggroup.h>
45 #include <config-runtime.h>
46 #include <kcomponentdata.h>
50 #include <phonon/mediaobject.h>
51 #include <phonon/path.h>
52 #include <phonon/audiooutput.h>
57 : media(new Phonon::MediaObject),
58 output(new Phonon::AudioOutput(Phonon::NotificationCategory))
60 Phonon::createPath(media, output);
63 inline void play(
const QString &file) { media->setCurrentSource(file); media->enqueue(Phonon::MediaSource()); media->play(); }
64 inline void stop() { media->stop(); }
65 inline void setVolume(
float volume) { output->setVolume(volume); }
69 output->deleteLater();
73 Phonon::MediaObject *
const media;
74 Phonon::AudioOutput *
const output;
80 PlayerPool() : m_idlePlayer(0), m_volume(1.0) {}
83 void returnPlayer(Player *);
86 void setVolume(
float volume);
90 QList<Player *> m_playersInUse;
94 Player *PlayerPool::getPlayer()
103 p->setVolume(m_volume);
108 void PlayerPool::returnPlayer(Player *p)
110 m_playersInUse.removeAll(p);
118 void PlayerPool::clear()
124 void PlayerPool::setVolume(
float v)
127 foreach (Player *p, m_playersInUse) {
132 class NotifyBySound::Private
135 enum { NoSound, UsePhonon, ExternalPlayer } playerMode;
136 QString externalPlayer;
138 QHash<int, KProcess *> processes;
139 QHash<int, Player*> playerObjects;
140 QSignalMapper *signalmapper;
141 PlayerPool playerPool;
142 QBasicTimer poolTimer;
143 QQueue<int> closeQueue;
151 d->signalmapper =
new QSignalMapper(
this);
152 connect(d->signalmapper, SIGNAL(mapped(
int)),
this, SLOT(slotSoundFinished(
int)));
164 void NotifyBySound::loadConfig()
167 KSharedConfig::Ptr kc = KGlobal::config();
168 KConfigGroup cg(kc,
"Sounds");
170 d->playerMode = Private::UsePhonon;
171 if(cg.readEntry(
"Use external player",
false ))
173 d->playerMode = Private::ExternalPlayer;
174 d->externalPlayer = cg.readPathEntry(
"External player", QString());
176 if ( d->externalPlayer.isEmpty() ) {
178 players <<
"wavplay" <<
"aplay" <<
"auplay" <<
"artsplay" <<
"akodeplay";
179 QStringList::const_iterator it = players.constBegin();
180 while ( d->externalPlayer.isEmpty() && it != players.constEnd() ) {
181 d->externalPlayer = KStandardDirs::findExe( *it );
186 else if(cg.readEntry(
"No sound" ,
false ))
188 d->playerMode = Private::NoSound;
191 setVolume( cg.readEntry(
"Volume", 100 ) );
199 if(d->playerMode == Private::NoSound)
205 if(d->playerObjects.contains(eventId) || d->processes.contains(eventId) )
212 KUrl soundFileURL = config->
readEntry(
"Sound" ,
true );
213 QString soundFile = soundFileURL.toLocalFile();
215 if (soundFile.isEmpty())
222 if ( KUrl::isRelativeUrl(soundFile) )
224 QString search = QString(
"%1/sounds/%2").arg(config->
appname).arg(soundFile);
225 search = KGlobal::mainComponent().dirs()->findResource(
"data", search);
226 if ( search.isEmpty() )
227 soundFile = KStandardDirs::locate(
"sound", soundFile );
231 if ( soundFile.isEmpty() )
237 kDebug() <<
" going to play " << soundFile;
240 if(d->playerMode == Private::UsePhonon)
242 Player *player = d->playerPool.getPlayer();
243 connect(player->media, SIGNAL(
finished()), d->signalmapper, SLOT(map()));
244 d->signalmapper->setMapping(player->media, eventId);
245 player->play(soundFile);
246 d->playerObjects.insert(eventId, player);
248 else if (d->playerMode == Private::ExternalPlayer && !d->externalPlayer.isEmpty())
251 KProcess *proc =
new KProcess(
this );
252 connect( proc, SIGNAL(
finished(
int, QProcess::ExitStatus)),
253 d->signalmapper, SLOT(map()) );
254 d->signalmapper->setMapping( proc , eventId );
256 (*proc) << d->externalPlayer << soundFile;
264 if ( volume<0 ) volume=0;
265 if ( volume>=100 ) volume=100;
267 d->playerPool.setVolume(d->volume / 100.0);
273 if (e->timerId() == d->poolTimer.timerId()) {
275 d->playerPool.clear();
278 KNotifyPlugin::timerEvent(e);
281 void NotifyBySound::slotSoundFinished(
int id)
284 if(d->playerObjects.contains(
id))
286 Player *player=d->playerObjects.take(
id);
287 disconnect(player->media, SIGNAL(
finished()), d->signalmapper, SLOT(map()));
288 d->playerPool.returnPlayer(player);
291 if(d->processes.contains(
id))
293 d->processes[id]->deleteLater();
294 d->processes.remove(
id);
303 d->closeQueue.enqueue(
id);
304 QTimer::singleShot(60000,
this, SLOT(closeNow()));
307 void NotifyBySound::closeNow()
309 const int id = d->closeQueue.dequeue();
310 if(d->playerObjects.contains(
id))
312 Player *p = d->playerObjects.take(
id);
314 d->playerPool.returnPlayer(p);
317 if(d->processes.contains(
id))
319 d->processes[id]->kill();
320 d->processes[id]->deleteLater();
321 d->processes.remove(
id);
325 #include "notifybysound.moc"
virtual void notify(int id, KNotifyConfig *config)
This function is called when the notification is sent.
QString readEntry(const QString &entry, bool path=false)
abstract class for KNotify actions
virtual void close(int id)
This function is called when the notification has been closed.
void finished(int id)
the presentation is finished.
void finish(int id)
emit the finished signal you MUST call this function for each call to notify(), even if you do nothin...
NotifyBySound(QObject *parent=0l)
void timerEvent(QTimerEvent *)
QString appname
the name of the application that triggered the notification
Represent the configuration for an event.