1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-09 07:36:48 +02:00

A sad, sad commit filled with code that can never run. :`-(

This commit is contained in:
Jeff Mitchell
2011-11-16 18:58:27 -05:00
parent a11651f563
commit 20dfb26808
3 changed files with 167 additions and 21 deletions

View File

@@ -107,6 +107,7 @@ AudioEngine::~AudioEngine()
QStringList QStringList
AudioEngine::supportedMimeTypes() const AudioEngine::supportedMimeTypes() const
{ {
QMutexLocker locker( &m_mimeTypeMutex );
if ( m_supportedMimeTypes.isEmpty() ) if ( m_supportedMimeTypes.isEmpty() )
{ {
m_supportedMimeTypes = Phonon::BackendCapabilities::availableMimeTypes(); m_supportedMimeTypes = Phonon::BackendCapabilities::availableMimeTypes();
@@ -122,7 +123,13 @@ AudioEngine::supportedMimeTypes() const
void void
AudioEngine::playPause() AudioEngine::playPause()
{ {
if ( isPlaying() ) if ( QThread::currentThread() != AudioEngine::instance()->thread() )
{
QMetaObject::invokeMethod( AudioEngine::instance(), "playPause" );
return;
}
if ( m_mediaObject->state() == Phonon::PlayingState )
pause(); pause();
else else
play(); play();
@@ -132,14 +139,21 @@ AudioEngine::playPause()
void void
AudioEngine::play() AudioEngine::play()
{ {
if ( QThread::currentThread() != AudioEngine::instance()->thread() )
{
QMetaObject::invokeMethod( AudioEngine::instance(), "play" );
return;
}
tDebug( LOGEXTRA ) << Q_FUNC_INFO; tDebug( LOGEXTRA ) << Q_FUNC_INFO;
if ( isPaused() ) if ( m_mediaObject->state() == Phonon::PausedState )
{ {
m_mediaObject->play(); m_mediaObject->play();
emit resumed(); emit resumed();
Tomahawk::InfoSystem::InfoStringHash trackInfo; Tomahawk::InfoSystem::InfoStringHash trackInfo;
QMutexLocker locker( &m_currentTrackMutex );
trackInfo["title"] = m_currentTrack->track(); trackInfo["title"] = m_currentTrack->track();
trackInfo["artist"] = m_currentTrack->artist()->name(); trackInfo["artist"] = m_currentTrack->artist()->name();
trackInfo["album"] = m_currentTrack->album()->name(); trackInfo["album"] = m_currentTrack->album()->name();
@@ -155,6 +169,12 @@ AudioEngine::play()
void void
AudioEngine::pause() AudioEngine::pause()
{ {
if ( QThread::currentThread() != AudioEngine::instance()->thread() )
{
QMetaObject::invokeMethod( AudioEngine::instance(), "pause" );
return;
}
tDebug( LOGEXTRA ) << Q_FUNC_INFO; tDebug( LOGEXTRA ) << Q_FUNC_INFO;
m_mediaObject->pause(); m_mediaObject->pause();
@@ -167,8 +187,15 @@ AudioEngine::pause()
void void
AudioEngine::stop() AudioEngine::stop()
{ {
if ( QThread::currentThread() != AudioEngine::instance()->thread() )
{
QMetaObject::invokeMethod( AudioEngine::instance(), "stop" );
return;
}
tDebug( LOGEXTRA ) << Q_FUNC_INFO; tDebug( LOGEXTRA ) << Q_FUNC_INFO;
if ( isStopped() ) QMutexLocker locker( &m_playlistMutex );
if ( m_mediaObject->state() == Phonon::StoppedState )
return; return;
setState( Stopped ); setState( Stopped );
@@ -176,8 +203,11 @@ AudioEngine::stop()
if ( !m_playlist.isNull() ) if ( !m_playlist.isNull() )
m_playlist.data()->reset(); m_playlist.data()->reset();
m_currentTrackMutex.lock();
if ( !m_currentTrack.isNull() ) if ( !m_currentTrack.isNull() )
emit timerPercentage( ( (double)m_timeElapsed / (double)m_currentTrack->duration() ) * 100.0 ); emit timerPercentage( ( (double)m_timeElapsed / (double)m_currentTrack->duration() ) * 100.0 );
m_currentTrackMutex.unlock();
emit stopped(); emit stopped();
setCurrentTrack( Tomahawk::result_ptr() ); setCurrentTrack( Tomahawk::result_ptr() );
@@ -203,6 +233,12 @@ AudioEngine::stop()
void void
AudioEngine::previous() AudioEngine::previous()
{ {
if ( QThread::currentThread() != AudioEngine::instance()->thread() )
{
QMetaObject::invokeMethod( AudioEngine::instance(), "previous" );
return;
}
tDebug( LOGEXTRA ) << Q_FUNC_INFO; tDebug( LOGEXTRA ) << Q_FUNC_INFO;
if ( canGoPrevious() ) if ( canGoPrevious() )
@@ -213,6 +249,12 @@ AudioEngine::previous()
void void
AudioEngine::next() AudioEngine::next()
{ {
if ( QThread::currentThread() != AudioEngine::instance()->thread() )
{
QMetaObject::invokeMethod( AudioEngine::instance(), "next" );
return;
}
tDebug( LOGEXTRA ) << Q_FUNC_INFO; tDebug( LOGEXTRA ) << Q_FUNC_INFO;
if ( canGoNext() ) if ( canGoNext() )
@@ -224,6 +266,9 @@ bool
AudioEngine::canGoNext() AudioEngine::canGoNext()
{ {
tDebug( LOGVERBOSE ) << Q_FUNC_INFO; tDebug( LOGVERBOSE ) << Q_FUNC_INFO;
QMutexLocker plocker( &m_playlistMutex );
QMutexLocker qlocker( &m_queueMutex );
QMutexLocker ctlocker( &m_currentTrackMutex );
if ( m_queue && m_queue->trackCount() ) if ( m_queue && m_queue->trackCount() )
return true; return true;
@@ -251,6 +296,7 @@ AudioEngine::canGoNext()
bool bool
AudioEngine::canGoPrevious() AudioEngine::canGoPrevious()
{ {
QMutexLocker locker( &m_playlistMutex );
if ( m_playlist.isNull() ) if ( m_playlist.isNull() )
return false; return false;
@@ -265,6 +311,7 @@ AudioEngine::canGoPrevious()
bool bool
AudioEngine::canSeek() AudioEngine::canSeek()
{ {
QMutexLocker locker( &m_playlistMutex );
bool phononCanSeek = true; bool phononCanSeek = true;
/* TODO: When phonon properly reports this, re-enable it /* TODO: When phonon properly reports this, re-enable it
if ( m_mediaObject && m_mediaObject->isValid() ) if ( m_mediaObject && m_mediaObject->isValid() )
@@ -277,13 +324,19 @@ AudioEngine::canSeek()
void void
AudioEngine::seek( qint64 ms ) AudioEngine::seek( qint64 ms )
{ {
if ( QThread::currentThread() != AudioEngine::instance()->thread() )
{
QMetaObject::invokeMethod( AudioEngine::instance(), "seek", Q_ARG( qint64, ms ) );
return;
}
if ( !canSeek() ) if ( !canSeek() )
{ {
tDebug( LOGEXTRA ) << "Could not seek!"; tDebug( LOGEXTRA ) << "Could not seek!";
return; return;
} }
if ( isPlaying() || isPaused() ) if ( m_mediaObject->state() == Phonon::PlayingState || m_mediaObject->state() == Phonon::PausedState )
{ {
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << ms; tDebug( LOGVERBOSE ) << Q_FUNC_INFO << ms;
m_mediaObject->seek( ms ); m_mediaObject->seek( ms );
@@ -302,6 +355,12 @@ AudioEngine::seek( int ms )
void void
AudioEngine::setVolume( int percentage ) AudioEngine::setVolume( int percentage )
{ {
if ( QThread::currentThread() != AudioEngine::instance()->thread() )
{
QMetaObject::invokeMethod( AudioEngine::instance(), "setVolume", Q_ARG( int, percentage ) );
return;
}
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << percentage; tDebug( LOGVERBOSE ) << Q_FUNC_INFO << percentage;
percentage = qBound( 0, percentage, 100 ); percentage = qBound( 0, percentage, 100 );
@@ -309,6 +368,27 @@ AudioEngine::setVolume( int percentage )
emit volumeChanged( percentage ); emit volumeChanged( percentage );
} }
void
AudioEngine::lowerVolume()
{
if ( QThread::currentThread() != AudioEngine::instance()->thread() )
{
QMetaObject::invokeMethod( AudioEngine::instance(), "lowerVolume" );
return;
}
setVolume( volume() - AUDIO_VOLUME_STEP );
}
void
AudioEngine::raiseVolume()
{
if ( QThread::currentThread() != AudioEngine::instance()->thread() )
{
QMetaObject::invokeMethod( AudioEngine::instance(), "raiseVolume" );
return;
}
setVolume( volume() + AUDIO_VOLUME_STEP );
}
void void
AudioEngine::mute() AudioEngine::mute()
@@ -344,6 +424,7 @@ AudioEngine::sendNowPlayingNotification()
m_infoSystemConnected = true; m_infoSystemConnected = true;
} }
QMutexLocker locker( &m_currentTrackMutex );
Tomahawk::InfoSystem::InfoStringHash trackInfo; Tomahawk::InfoSystem::InfoStringHash trackInfo;
trackInfo["artist"] = m_currentTrack->album()->artist()->name(); trackInfo["artist"] = m_currentTrack->album()->artist()->name();
trackInfo["album"] = m_currentTrack->album()->name(); trackInfo["album"] = m_currentTrack->album()->name();
@@ -361,6 +442,7 @@ AudioEngine::sendNowPlayingNotification()
void void
AudioEngine::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) AudioEngine::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output )
{ {
QMutexLocker locker( &m_currentTrackMutex );
if ( requestData.caller != s_aeInfoIdentifier || if ( requestData.caller != s_aeInfoIdentifier ||
requestData.type != Tomahawk::InfoSystem::InfoAlbumCoverArt ) requestData.type != Tomahawk::InfoSystem::InfoAlbumCoverArt )
{ {
@@ -434,6 +516,7 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
{ {
setCurrentTrack( result ); setCurrentTrack( result );
QMutexLocker locker( &m_currentTrackMutex );
if ( !isHttpResult( m_currentTrack->url() ) && !isLocalResult( m_currentTrack->url() ) ) if ( !isHttpResult( m_currentTrack->url() ) && !isLocalResult( m_currentTrack->url() ) )
{ {
io = Servent::instance()->getIODeviceForUrl( m_currentTrack ); io = Servent::instance()->getIODeviceForUrl( m_currentTrack );
@@ -448,6 +531,7 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
if ( !err ) if ( !err )
{ {
QMutexLocker locker( &m_currentTrackMutex );
tLog() << "Starting new song:" << m_currentTrack->url(); tLog() << "Starting new song:" << m_currentTrack->url();
emit loading( m_currentTrack ); emit loading( m_currentTrack );
@@ -531,6 +615,7 @@ void
AudioEngine::loadPreviousTrack() AudioEngine::loadPreviousTrack()
{ {
tDebug( LOGEXTRA ) << Q_FUNC_INFO; tDebug( LOGEXTRA ) << Q_FUNC_INFO;
QMutexLocker locker( &m_playlistMutex );
if ( m_playlist.isNull() ) if ( m_playlist.isNull() )
{ {
@@ -550,6 +635,8 @@ void
AudioEngine::loadNextTrack() AudioEngine::loadNextTrack()
{ {
tDebug( LOGEXTRA ) << Q_FUNC_INFO; tDebug( LOGEXTRA ) << Q_FUNC_INFO;
QMutexLocker plocker( &m_playlistMutex );
QMutexLocker qlocker( &m_queueMutex );
Tomahawk::result_ptr result; Tomahawk::result_ptr result;
@@ -562,7 +649,9 @@ AudioEngine::loadNextTrack()
{ {
tDebug( LOGEXTRA ) << Q_FUNC_INFO << "Loading playlist's next item"; tDebug( LOGEXTRA ) << Q_FUNC_INFO << "Loading playlist's next item";
result = m_playlist.data()->nextItem(); result = m_playlist.data()->nextItem();
m_currentTrackPlaylistMutex.lock();
m_currentTrackPlaylist = m_playlist; m_currentTrackPlaylist = m_playlist;
m_currentTrackPlaylistMutex.unlock();
} }
if ( !result.isNull() ) if ( !result.isNull() )
@@ -583,20 +672,29 @@ AudioEngine::loadNextTrack()
void void
AudioEngine::playItem( Tomahawk::PlaylistInterface* playlist, const Tomahawk::result_ptr& result ) AudioEngine::playItem( Tomahawk::PlaylistInterface* playlist, const Tomahawk::result_ptr& result )
{ {
if ( QThread::currentThread() != AudioEngine::instance()->thread() )
{
QMetaObject::invokeMethod( AudioEngine::instance(), "playItem", Q_ARG( Tomahawk::PlaylistInterface*, playlist ), Q_ARG( const Tomahawk::result_ptr&, result ) );
return;
}
tDebug( LOGEXTRA ) << Q_FUNC_INFO << ( result.isNull() ? QString() : result->url() ); tDebug( LOGEXTRA ) << Q_FUNC_INFO << ( result.isNull() ? QString() : result->url() );
QMutexLocker locker( &m_playlistMutex );
if ( !m_playlist.isNull() ) if ( !m_playlist.isNull() )
m_playlist.data()->reset(); m_playlist.data()->reset();
setPlaylist( playlist ); setPlaylist( playlist );
m_currentTrackPlaylistMutex.lock();
m_currentTrackPlaylist = playlist->getSharedPointer(); m_currentTrackPlaylist = playlist->getSharedPointer();
m_currentTrackPlaylistMutex.unlock();
if ( !result.isNull() ) if ( !result.isNull() )
loadTrack( result ); loadTrack( result );
else if ( !m_playlist.isNull() && m_playlist.data()->retryMode() == PlaylistInterface::Retry ) else if ( !m_playlist.isNull() && m_playlist.data()->retryMode() == PlaylistInterface::Retry )
{ {
m_waitingOnNewTrack = true; m_waitingOnNewTrack = true;
if ( isStopped() ) if ( m_mediaObject->state() == Phonon::StoppedState )
sendWaitingNotification(); sendWaitingNotification();
else else
stop(); stop();
@@ -627,6 +725,9 @@ void
AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState ) AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState )
{ {
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << oldState << newState << m_expectStop; tDebug( LOGVERBOSE ) << Q_FUNC_INFO << oldState << newState << m_expectStop;
QMutexLocker plocker( &m_playlistMutex );
QMutexLocker vlocker( &m_volumeMutex );
m_volume = m_audioOutput->volume() * 100.0;
if ( newState == Phonon::ErrorState ) if ( newState == Phonon::ErrorState )
{ {
@@ -634,7 +735,11 @@ AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState )
return; return;
} }
if ( newState == Phonon::PlayingState ) if ( newState == Phonon::PlayingState )
{
QMutexLocker locker( &m_currentTrackMutex );
m_currentTrackTotalTime = m_mediaObject->totalTime() > 0 ? m_mediaObject->totalTime() : m_currentTrack->duration() * 1000;
setState( Playing ); setState( Playing );
}
if ( oldState == Phonon::PlayingState ) if ( oldState == Phonon::PlayingState )
{ {
@@ -643,6 +748,7 @@ AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState )
{ {
case Phonon::PausedState: case Phonon::PausedState:
{ {
QMutexLocker locker( &m_currentTrackMutex );
qint64 duration = m_mediaObject->totalTime() > 0 ? m_mediaObject->totalTime() : m_currentTrack->duration() * 1000; qint64 duration = m_mediaObject->totalTime() > 0 ? m_mediaObject->totalTime() : m_currentTrack->duration() * 1000;
stopped = ( duration - 1000 < m_mediaObject->currentTime() ); stopped = ( duration - 1000 < m_mediaObject->currentTime() );
if ( !stopped ) if ( !stopped )
@@ -679,6 +785,8 @@ AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState )
void void
AudioEngine::timerTriggered( qint64 time ) AudioEngine::timerTriggered( qint64 time )
{ {
QMutexLocker locker( &m_currentTrackMutex );
m_currentTime = time;
emit timerMilliSeconds( time ); emit timerMilliSeconds( time );
if ( m_timeElapsed != time / 1000 ) if ( m_timeElapsed != time / 1000 )
@@ -704,6 +812,14 @@ AudioEngine::timerTriggered( qint64 time )
void void
AudioEngine::setPlaylist( PlaylistInterface* playlist ) AudioEngine::setPlaylist( PlaylistInterface* playlist )
{ {
if ( QThread::currentThread() != AudioEngine::instance()->thread() )
{
QMetaObject::invokeMethod( AudioEngine::instance(), "setPlaylist", Q_ARG( Tomahawk::PlaylistInterface*, playlist ) );
return;
}
QMutexLocker locker( &m_playlistMutex );
if ( !m_playlist.isNull() ) if ( !m_playlist.isNull() )
{ {
if ( m_playlist.data()->object() && m_playlist.data()->retryMode() == PlaylistInterface::Retry ) if ( m_playlist.data()->object() && m_playlist.data()->retryMode() == PlaylistInterface::Retry )
@@ -727,9 +843,25 @@ AudioEngine::setPlaylist( PlaylistInterface* playlist )
} }
void
AudioEngine::setQueue( Tomahawk::PlaylistInterface* queue )
{
if ( QThread::currentThread() != AudioEngine::instance()->thread() )
{
QMetaObject::invokeMethod( AudioEngine::instance(), "setQueue", Q_ARG( Tomahawk::PlaylistInterface*, queue ) );
return;
}
QMutexLocker locker( &m_queueMutex );
m_queue = queue;
}
void void
AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result ) AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result )
{ {
QMutexLocker locker( &m_currentTrackMutex );
m_lastTrack = m_currentTrack; m_lastTrack = m_currentTrack;
if ( !m_lastTrack.isNull() ) if ( !m_lastTrack.isNull() )
{ {
@@ -763,6 +895,7 @@ AudioEngine::isLocalResult( const QString& url ) const
void void
AudioEngine::setState( AudioState state ) AudioEngine::setState( AudioState state )
{ {
QMutexLocker locker( &m_stateMutex );
AudioState oldState = m_state; AudioState oldState = m_state;
m_state = state; m_state = state;

View File

@@ -55,23 +55,23 @@ public:
~AudioEngine(); ~AudioEngine();
QStringList supportedMimeTypes() const; QStringList supportedMimeTypes() const;
unsigned int volume() const { return m_audioOutput->volume() * 100.0; } // in percent unsigned int volume() const { return m_volume; } // in percent
AudioState state() const { return m_state; } AudioState state() const { QMutexLocker locker( &m_stateMutex ); return m_state; }
bool isPlaying() const { return m_state == Playing; } bool isPlaying() const { QMutexLocker locker( &m_stateMutex ); return m_state == Playing; }
bool isPaused() const { return m_state == Paused; } bool isPaused() const { QMutexLocker locker( &m_stateMutex ); return m_state == Paused; }
bool isStopped() const { return m_state == Stopped; } bool isStopped() const { QMutexLocker locker( &m_stateMutex ); return m_state == Stopped; }
/* Returns the PlaylistInterface of the currently playing track. Note: This might be different to the current playlist! */ /* Returns the PlaylistInterface of the currently playing track. Note: This might be different to the current playlist! */
Tomahawk::PlaylistInterface* currentTrackPlaylist() const { return m_currentTrackPlaylist.data(); } Tomahawk::PlaylistInterface* currentTrackPlaylist() const { QMutexLocker locker( &m_currentTrackPlaylistMutex ); return m_currentTrackPlaylist.data(); }
/* Returns the PlaylistInterface of the current playlist. Note: The currently playing track might still be from a different playlist! */ /* Returns the PlaylistInterface of the current playlist. Note: The currently playing track might still be from a different playlist! */
Tomahawk::PlaylistInterface* playlist() const { return m_playlist.data(); } Tomahawk::PlaylistInterface* playlist() const { QMutexLocker locker( &m_playlistMutex ); return m_playlist.data(); }
Tomahawk::result_ptr currentTrack() const { return m_currentTrack; } Tomahawk::result_ptr currentTrack() const { QMutexLocker locker( &m_currentTrackMutex ); return m_currentTrack; }
qint64 currentTime() const { return m_mediaObject->currentTime(); } qint64 currentTime() const { QMutexLocker locker( &m_currentTrackMutex ); return m_currentTime; }
qint64 currentTrackTotalTime() const { return m_mediaObject->totalTime(); } qint64 currentTrackTotalTime() const { QMutexLocker locker( &m_currentTrackMutex ); return m_currentTrackTotalTime; }
public slots: public slots:
void playPause(); void playPause();
@@ -89,14 +89,14 @@ public slots:
void seek( qint64 ms ); void seek( qint64 ms );
void seek( int ms ); // for compatibility with seekbar in audiocontrols void seek( int ms ); // for compatibility with seekbar in audiocontrols
void setVolume( int percentage ); void setVolume( int percentage );
void lowerVolume() { setVolume( volume() - AUDIO_VOLUME_STEP ); } void lowerVolume();
void raiseVolume() { setVolume( volume() + AUDIO_VOLUME_STEP ); } void raiseVolume();
void onVolumeChanged( qreal volume ) { emit volumeChanged( volume * 100 ); } void onVolumeChanged( qreal volume ) { QMutexLocker locker( &m_volumeMutex ); m_volume = volume * 100; emit volumeChanged( volume * 100 ); }
void mute(); void mute();
void playItem( Tomahawk::PlaylistInterface* playlist, const Tomahawk::result_ptr& result ); void playItem( Tomahawk::PlaylistInterface* playlist, const Tomahawk::result_ptr& result );
void setPlaylist( Tomahawk::PlaylistInterface* playlist ); void setPlaylist( Tomahawk::PlaylistInterface* playlist );
void setQueue( Tomahawk::PlaylistInterface* queue ) { m_queue = queue; } void setQueue( Tomahawk::PlaylistInterface* queue );
void playlistNextTrackReady(); void playlistNextTrackReady();
@@ -167,6 +167,18 @@ private:
AudioState m_state; AudioState m_state;
static AudioEngine* s_instance; static AudioEngine* s_instance;
mutable QMutex m_stateMutex;
mutable QMutex m_mimeTypeMutex;
mutable QMutex m_currentTrackMutex;
mutable QMutex m_currentTrackPlaylistMutex;
mutable QMutex m_playlistMutex;
mutable QMutex m_queueMutex;
mutable QMutex m_volumeMutex;
qint64 m_currentTime;
qint64 m_currentTrackTotalTime;
unsigned int m_volume;
}; };
#endif // AUDIOENGINE_H #endif // AUDIOENGINE_H

View File

@@ -416,6 +416,7 @@ TomahawkApp::registerMetaTypes()
qRegisterMetaType< QList<Tomahawk::source_ptr> >("QList<Tomahawk::source_ptr>"); qRegisterMetaType< QList<Tomahawk::source_ptr> >("QList<Tomahawk::source_ptr>");
qRegisterMetaType< QMap< QString, Tomahawk::plentry_ptr > >("QMap< QString, Tomahawk::plentry_ptr >"); qRegisterMetaType< QMap< QString, Tomahawk::plentry_ptr > >("QMap< QString, Tomahawk::plentry_ptr >");
qRegisterMetaType< Tomahawk::PlaylistRevision >("Tomahawk::PlaylistRevision"); qRegisterMetaType< Tomahawk::PlaylistRevision >("Tomahawk::PlaylistRevision");
qRegisterMetaType< Tomahawk::PlaylistInterface* >( "Tomahawk::PlaylistInterface*" );
qRegisterMetaType< Tomahawk::DynamicPlaylistRevision >("Tomahawk::DynamicPlaylistRevision"); qRegisterMetaType< Tomahawk::DynamicPlaylistRevision >("Tomahawk::DynamicPlaylistRevision");
qRegisterMetaType< Tomahawk::QID >("Tomahawk::QID"); qRegisterMetaType< Tomahawk::QID >("Tomahawk::QID");