mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-09-11 22:50:49 +02:00
Compare commits
2 Commits
qt4
...
threadedau
Author | SHA1 | Date | |
---|---|---|---|
|
20dfb26808 | ||
|
a11651f563 |
@@ -292,7 +292,7 @@ set( libSources
|
|||||||
sip/sipinfo.cpp
|
sip/sipinfo.cpp
|
||||||
|
|
||||||
audio/audioengine.cpp
|
audio/audioengine.cpp
|
||||||
|
audio/audioenginethread.cpp
|
||||||
|
|
||||||
database/database.cpp
|
database/database.cpp
|
||||||
database/fuzzyindex.cpp
|
database/fuzzyindex.cpp
|
||||||
@@ -408,6 +408,7 @@ set( libHeaders
|
|||||||
sip/sipinfo.h
|
sip/sipinfo.h
|
||||||
|
|
||||||
audio/audioengine.h
|
audio/audioengine.h
|
||||||
|
audio/audioenginethread.h
|
||||||
|
|
||||||
database/database.h
|
database/database.h
|
||||||
database/fuzzyindex.h
|
database/fuzzyindex.h
|
||||||
|
@@ -100,12 +100,14 @@ AudioEngine::~AudioEngine()
|
|||||||
|
|
||||||
delete m_audioOutput;
|
delete m_audioOutput;
|
||||||
delete m_mediaObject;
|
delete m_mediaObject;
|
||||||
|
s_instance = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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();
|
||||||
@@ -121,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();
|
||||||
@@ -131,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();
|
||||||
@@ -154,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();
|
||||||
@@ -166,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 );
|
||||||
@@ -175,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() );
|
||||||
@@ -202,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() )
|
||||||
@@ -212,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() )
|
||||||
@@ -223,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;
|
||||||
@@ -250,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;
|
||||||
|
|
||||||
@@ -264,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() )
|
||||||
@@ -276,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 );
|
||||||
@@ -301,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 );
|
||||||
@@ -308,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()
|
||||||
@@ -343,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();
|
||||||
@@ -360,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 )
|
||||||
{
|
{
|
||||||
@@ -433,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 );
|
||||||
@@ -447,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 );
|
||||||
|
|
||||||
@@ -530,7 +615,8 @@ 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() )
|
||||||
{
|
{
|
||||||
stop();
|
stop();
|
||||||
@@ -549,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;
|
||||||
|
|
||||||
@@ -561,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() )
|
||||||
@@ -582,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();
|
||||||
@@ -626,14 +725,21 @@ 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 )
|
||||||
{
|
{
|
||||||
tLog() << "Phonon Error:" << m_mediaObject->errorString() << m_mediaObject->errorType();
|
tLog() << "Phonon Error:" << m_mediaObject->errorString() << m_mediaObject->errorType();
|
||||||
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 )
|
||||||
{
|
{
|
||||||
@@ -642,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 )
|
||||||
@@ -678,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 )
|
||||||
@@ -703,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 )
|
||||||
@@ -726,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() )
|
||||||
{
|
{
|
||||||
@@ -762,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;
|
||||||
|
|
||||||
|
@@ -19,8 +19,9 @@
|
|||||||
#ifndef AUDIOENGINE_H
|
#ifndef AUDIOENGINE_H
|
||||||
#define AUDIOENGINE_H
|
#define AUDIOENGINE_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QtCore/QObject>
|
||||||
#include <QTimer>
|
#include <QtCore/QTimer>
|
||||||
|
#include <QtCore/QMutex>
|
||||||
|
|
||||||
#include <phonon/MediaObject>
|
#include <phonon/MediaObject>
|
||||||
#include <phonon/AudioOutput>
|
#include <phonon/AudioOutput>
|
||||||
@@ -54,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();
|
||||||
@@ -88,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();
|
||||||
|
|
||||||
@@ -166,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
|
||||||
|
41
src/libtomahawk/audio/audioenginethread.cpp
Normal file
41
src/libtomahawk/audio/audioenginethread.cpp
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||||
|
*
|
||||||
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tomahawk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "audioenginethread.h"
|
||||||
|
#include <utils/logger.h>
|
||||||
|
#include <audio/audioengine.h>
|
||||||
|
|
||||||
|
AudioEngineThread::AudioEngineThread( QObject *parent )
|
||||||
|
: QThread( parent )
|
||||||
|
{
|
||||||
|
tDebug() << Q_FUNC_INFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioEngineThread::~AudioEngineThread()
|
||||||
|
{
|
||||||
|
tDebug() << Q_FUNC_INFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioEngineThread::AudioEngineThread::run()
|
||||||
|
{
|
||||||
|
m_audioEngine = QWeakPointer< AudioEngine >( new AudioEngine() );
|
||||||
|
exec();
|
||||||
|
if( !m_audioEngine.isNull() )
|
||||||
|
delete m_audioEngine.data();
|
||||||
|
}
|
44
src/libtomahawk/audio/audioenginethread.h
Normal file
44
src/libtomahawk/audio/audioenginethread.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||||
|
*
|
||||||
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tomahawk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AUDIOENGINETHREAD_H
|
||||||
|
#define AUDIOENGINETHREAD_H
|
||||||
|
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
#include <QtCore/QThread>
|
||||||
|
#include <QtCore/QWeakPointer>
|
||||||
|
|
||||||
|
#include "dllmacro.h"
|
||||||
|
|
||||||
|
class AudioEngine;
|
||||||
|
|
||||||
|
class DLLEXPORT AudioEngineThread : public QThread
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
AudioEngineThread( QObject *parent = 0 );
|
||||||
|
virtual ~AudioEngineThread();
|
||||||
|
|
||||||
|
void run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWeakPointer< AudioEngine > m_audioEngine;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // AUDIOENGINETHREAD_H
|
@@ -21,14 +21,15 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <QPluginLoader>
|
#include <QtCore/QPluginLoader>
|
||||||
#include <QDir>
|
#include <QtCore/QDir>
|
||||||
#include <QMetaType>
|
#include <QtCore/QMetaType>
|
||||||
#include <QTime>
|
#include <QtCore/QTime>
|
||||||
#include <QNetworkReply>
|
#include <QtNetwork/QNetworkReply>
|
||||||
#include <QFile>
|
#include <QtCore/QFile>
|
||||||
#include <QFileInfo>
|
#include <QtCore/QFileInfo>
|
||||||
#include <QNetworkProxy>
|
#include <QtNetwork/QNetworkProxy>
|
||||||
|
#include <QtCore/QThread>
|
||||||
|
|
||||||
#include "actioncollection.h"
|
#include "actioncollection.h"
|
||||||
#include "artist.h"
|
#include "artist.h"
|
||||||
@@ -57,6 +58,7 @@
|
|||||||
#include "EchonestCatalogSynchronizer.h"
|
#include "EchonestCatalogSynchronizer.h"
|
||||||
|
|
||||||
#include "audio/audioengine.h"
|
#include "audio/audioengine.h"
|
||||||
|
#include "audio/audioenginethread.h"
|
||||||
#include "utils/xspfloader.h"
|
#include "utils/xspfloader.h"
|
||||||
#include "utils/jspfloader.h"
|
#include "utils/jspfloader.h"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
@@ -70,7 +72,7 @@
|
|||||||
#include "AtticaManager.h"
|
#include "AtticaManager.h"
|
||||||
#include "tomahawkwindow.h"
|
#include "tomahawkwindow.h"
|
||||||
#include "settingsdialog.h"
|
#include "settingsdialog.h"
|
||||||
#include <QMessageBox>
|
#include <QtGui/QMessageBox>
|
||||||
#include "widgets/HeaderLabel.h"
|
#include "widgets/HeaderLabel.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -165,11 +167,13 @@ TomahawkApp::init()
|
|||||||
// Cause the creation of the nam, but don't need to address it directly, so prevent warning
|
// Cause the creation of the nam, but don't need to address it directly, so prevent warning
|
||||||
Q_UNUSED( TomahawkUtils::nam() );
|
Q_UNUSED( TomahawkUtils::nam() );
|
||||||
|
|
||||||
m_audioEngine = QWeakPointer<AudioEngine>( new AudioEngine );
|
m_audioEngineThread = QWeakPointer< AudioEngineThread >( new AudioEngineThread( this ) );
|
||||||
m_scanManager = QWeakPointer<ScanManager>( new ScanManager( this ) );
|
m_audioEngineThread.data()->start( QThread::HighPriority );
|
||||||
|
|
||||||
|
m_scanManager = QWeakPointer< ScanManager >( new ScanManager( this ) );
|
||||||
new Pipeline( this );
|
new Pipeline( this );
|
||||||
|
|
||||||
m_servent = QWeakPointer<Servent>( new Servent( this ) );
|
m_servent = QWeakPointer< Servent >( new Servent( this ) );
|
||||||
connect( m_servent.data(), SIGNAL( ready() ), SLOT( initSIP() ) );
|
connect( m_servent.data(), SIGNAL( ready() ), SLOT( initSIP() ) );
|
||||||
|
|
||||||
tDebug() << "Init Database.";
|
tDebug() << "Init Database.";
|
||||||
@@ -198,16 +202,17 @@ TomahawkApp::init()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Connect up shortcuts
|
// Connect up shortcuts
|
||||||
if ( !m_shortcutHandler.isNull() )
|
if ( !m_shortcutHandler.isNull() && AudioEngine::instance() )
|
||||||
{
|
{
|
||||||
connect( m_shortcutHandler.data(), SIGNAL( playPause() ), m_audioEngine.data(), SLOT( playPause() ) );
|
AudioEngine* audioEngine = AudioEngine::instance();
|
||||||
connect( m_shortcutHandler.data(), SIGNAL( pause() ), m_audioEngine.data(), SLOT( pause() ) );
|
connect( m_shortcutHandler.data(), SIGNAL( playPause() ), audioEngine, SLOT( playPause() ) );
|
||||||
connect( m_shortcutHandler.data(), SIGNAL( stop() ), m_audioEngine.data(), SLOT( stop() ) );
|
connect( m_shortcutHandler.data(), SIGNAL( pause() ), audioEngine, SLOT( pause() ) );
|
||||||
connect( m_shortcutHandler.data(), SIGNAL( previous() ), m_audioEngine.data(), SLOT( previous() ) );
|
connect( m_shortcutHandler.data(), SIGNAL( stop() ), audioEngine, SLOT( stop() ) );
|
||||||
connect( m_shortcutHandler.data(), SIGNAL( next() ), m_audioEngine.data(), SLOT( next() ) );
|
connect( m_shortcutHandler.data(), SIGNAL( previous() ), audioEngine, SLOT( previous() ) );
|
||||||
connect( m_shortcutHandler.data(), SIGNAL( volumeUp() ), m_audioEngine.data(), SLOT( raiseVolume() ) );
|
connect( m_shortcutHandler.data(), SIGNAL( next() ), audioEngine, SLOT( next() ) );
|
||||||
connect( m_shortcutHandler.data(), SIGNAL( volumeDown() ), m_audioEngine.data(), SLOT( lowerVolume() ) );
|
connect( m_shortcutHandler.data(), SIGNAL( volumeUp() ), audioEngine, SLOT( raiseVolume() ) );
|
||||||
connect( m_shortcutHandler.data(), SIGNAL( mute() ), m_audioEngine.data(), SLOT( mute() ) );
|
connect( m_shortcutHandler.data(), SIGNAL( volumeDown() ), audioEngine, SLOT( lowerVolume() ) );
|
||||||
|
connect( m_shortcutHandler.data(), SIGNAL( mute() ), audioEngine, SLOT( mute() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
tDebug() << "Init InfoSystem.";
|
tDebug() << "Init InfoSystem.";
|
||||||
@@ -293,8 +298,14 @@ TomahawkApp::~TomahawkApp()
|
|||||||
if ( !m_scanManager.isNull() )
|
if ( !m_scanManager.isNull() )
|
||||||
delete m_scanManager.data();
|
delete m_scanManager.data();
|
||||||
|
|
||||||
if ( !m_audioEngine.isNull() )
|
if ( AudioEngine::instance() )
|
||||||
delete m_audioEngine.data();
|
{
|
||||||
|
m_audioEngineThread.data()->quit();
|
||||||
|
m_audioEngineThread.data()->wait( 60000 );
|
||||||
|
|
||||||
|
delete m_audioEngineThread.data();
|
||||||
|
m_audioEngineThread.clear();
|
||||||
|
}
|
||||||
|
|
||||||
if ( !m_infoSystem.isNull() )
|
if ( !m_infoSystem.isNull() )
|
||||||
delete m_infoSystem.data();
|
delete m_infoSystem.data();
|
||||||
@@ -405,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");
|
||||||
|
|
||||||
|
@@ -24,11 +24,11 @@
|
|||||||
#include "headlesscheck.h"
|
#include "headlesscheck.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <QRegExp>
|
#include <QtCore/QRegExp>
|
||||||
#include <QFile>
|
#include <QtCore/QFile>
|
||||||
#include <QSettings>
|
#include <QtCore/QSettings>
|
||||||
#include <QDir>
|
#include <QtCore/QDir>
|
||||||
#include <QPersistentModelIndex>
|
#include <QtCore/QPersistentModelIndex>
|
||||||
|
|
||||||
#include "QxtHttpServerConnector"
|
#include "QxtHttpServerConnector"
|
||||||
#include "QxtHttpSessionManager"
|
#include "QxtHttpSessionManager"
|
||||||
@@ -38,6 +38,7 @@
|
|||||||
#include "utils/tomahawkutils.h"
|
#include "utils/tomahawkutils.h"
|
||||||
#include "thirdparty/kdsingleapplicationguard/kdsingleapplicationguard.h"
|
#include "thirdparty/kdsingleapplicationguard/kdsingleapplicationguard.h"
|
||||||
|
|
||||||
|
class AudioEngineThread;
|
||||||
class AudioEngine;
|
class AudioEngine;
|
||||||
class Database;
|
class Database;
|
||||||
class ScanManager;
|
class ScanManager;
|
||||||
@@ -113,7 +114,7 @@ private:
|
|||||||
|
|
||||||
QWeakPointer<Database> m_database;
|
QWeakPointer<Database> m_database;
|
||||||
QWeakPointer<ScanManager> m_scanManager;
|
QWeakPointer<ScanManager> m_scanManager;
|
||||||
QWeakPointer<AudioEngine> m_audioEngine;
|
QWeakPointer<AudioEngineThread> m_audioEngineThread;
|
||||||
QWeakPointer<Servent> m_servent;
|
QWeakPointer<Servent> m_servent;
|
||||||
QWeakPointer<Tomahawk::InfoSystem::InfoSystem> m_infoSystem;
|
QWeakPointer<Tomahawk::InfoSystem::InfoSystem> m_infoSystem;
|
||||||
QWeakPointer<XMPPBot> m_xmppBot;
|
QWeakPointer<XMPPBot> m_xmppBot;
|
||||||
|
Reference in New Issue
Block a user