1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-04-15 13:32:35 +02:00

* Initial work on phonon-powered AudioEngine.

This commit is contained in:
Christian Muehlhaeuser 2011-01-14 15:10:19 +01:00
parent a4e140972e
commit 41512c4b61
3 changed files with 35 additions and 234 deletions

View File

@ -7,6 +7,8 @@ ENDIF()
SET( QT_USE_QTSQL TRUE )
SET( QT_USE_QTNETWORK TRUE )
SET( QT_USE_QTXML TRUE )
SET( QT_USE_PHONON TRUE )
INCLUDE( ${QT_USE_FILE} )
INCLUDE( ${CMAKE_MODULE_PATH}/AddAppIconMacro.cmake )
@ -27,9 +29,6 @@ SET( TOMAHAWK_INC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../include/" )
#ENDFOREACH( moddir )
SET( tomahawkSources ${tomahawkSources}
audio/madtranscode.cpp
audio/vorbistranscode.cpp
audio/flactranscode.cpp
audio/audioengine.cpp
utils/tomahawkutils.cpp
@ -113,9 +112,6 @@ SET( tomahawkHeaders ${tomahawkHeaders}
"${TOMAHAWK_INC_DIR}/tomahawk/infosystem.h"
audio/transcodeinterface.h
audio/madtranscode.h
audio/vorbistranscode.h
audio/flactranscode.h
audio/audioengine.h
sip/SipHandler.h
@ -215,7 +211,6 @@ INCLUDE_DIRECTORIES(
utils
libtomahawk
../rtaudio
../alsa-playback
../qxt/qxtweb-standalone/qxtweb

View File

@ -1,7 +1,6 @@
#include "audioengine.h"
#include <QUrl>
#include <QMutexLocker>
#include "playlistinterface.h"
@ -9,47 +8,36 @@
#include "database/databasecommand_logplayback.h"
#include "network/servent.h"
#include "madtranscode.h"
#ifndef NO_OGG
#include "vorbistranscode.h"
#endif
#ifndef NO_FLAC
#include "flactranscode.h"
#endif
AudioEngine::AudioEngine()
: QThread()
: QObject()
, m_playlist( 0 )
, m_currentTrackPlaylist( 0 )
, m_queue( 0 )
, m_timeElapsed( 0 )
, m_i( 0 )
{
qDebug() << "Init AudioEngine";
moveToThread( this );
qRegisterMetaType< AudioErrorCode >("AudioErrorCode");
#ifdef Q_WS_X11
m_audio = new AlsaPlayback();
#else
m_audio = new RTAudioOutput();
#endif
connect( m_audio, SIGNAL( timeElapsed( unsigned int ) ), SLOT( timerTriggered( unsigned int ) ), Qt::DirectConnection );
m_mediaObject = new Phonon::MediaObject( this );
m_audioOutput = new Phonon::AudioOutput( Phonon::MusicCategory, this );
Phonon::createPath( m_mediaObject, m_audioOutput );
start();
// connect( m_audio, SIGNAL( timeElapsed( unsigned int ) ), SLOT( timerTriggered( unsigned int ) ), Qt::DirectConnection );
}
AudioEngine::~AudioEngine()
{
qDebug() << Q_FUNC_INFO << "waiting for event loop to finish...";
quit();
wait( 1000 );
m_mediaObject->stop();
delete m_audioOutput;
delete m_mediaObject;
m_input.clear();
delete m_audio;
}
@ -58,10 +46,9 @@ AudioEngine::play()
{
qDebug() << Q_FUNC_INFO;
if ( m_audio->isPaused() )
if ( isPaused() )
{
QMutexLocker lock( &m_mutex );
m_audio->resume();
m_mediaObject->play();
emit resumed();
}
else
@ -73,9 +60,8 @@ void
AudioEngine::pause()
{
qDebug() << Q_FUNC_INFO;
QMutexLocker lock( &m_mutex );
m_audio->pause();
m_mediaObject->pause();
emit paused();
}
@ -84,7 +70,8 @@ void
AudioEngine::stop()
{
qDebug() << Q_FUNC_INFO;
QMutexLocker lock( &m_mutex );
m_mediaObject->stop();
if ( !m_input.isNull() )
{
@ -92,11 +79,6 @@ AudioEngine::stop()
m_input.clear();
}
if ( !m_transcode.isNull() )
m_transcode->clearBuffers();
m_audio->stopPlayback();
setCurrentTrack( Tomahawk::result_ptr() );
emit stopped();
}
@ -106,7 +88,6 @@ void
AudioEngine::previous()
{
qDebug() << Q_FUNC_INFO;
clearBuffers();
loadPreviousTrack();
}
@ -115,7 +96,6 @@ void
AudioEngine::next()
{
qDebug() << Q_FUNC_INFO;
clearBuffers();
loadNextTrack();
}
@ -127,7 +107,7 @@ AudioEngine::setVolume( int percentage )
percentage = qBound( 0, percentage, 100 );
m_audio->setVolume( percentage );
m_audioOutput->setVolume( (qreal)percentage / 100.0 );
emit volumeChanged( percentage );
}
@ -149,9 +129,7 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
qDebug() << Q_FUNC_INFO << thread() << result;
bool err = false;
// in a separate scope due to the QMutexLocker!
{
QMutexLocker lock( &m_mutex );
QSharedPointer<QIODevice> io;
if ( result.isNull() )
@ -181,44 +159,15 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
m_input.clear();
}
if ( m_lastTrack.isNull() || ( m_currentTrack->mimetype() != m_lastTrack->mimetype() ) )
{
if ( !m_transcode.isNull() )
{
m_transcode.clear();
}
m_input = io;
if ( m_currentTrack->mimetype() == "audio/mpeg" )
{
m_transcode = QSharedPointer<TranscodeInterface>(new MADTranscode());
}
#ifndef NO_OGG
else if ( m_currentTrack->mimetype() == "application/ogg" )
{
m_transcode = QSharedPointer<TranscodeInterface>(new VorbisTranscode());
}
#endif
#ifndef NO_FLAC
else if ( m_currentTrack->mimetype() == "audio/flac" )
{
m_transcode = QSharedPointer<TranscodeInterface>(new FLACTranscode());
}
#endif
else
qDebug() << "Could NOT find suitable transcoder! Stopping audio.";
m_mediaObject->setCurrentSource( io.data() ) ;
m_mediaObject->play();
if ( !m_transcode.isNull() )
connect( m_transcode.data(), SIGNAL( streamInitialized( long, int ) ), SLOT( setStreamData( long, int ) ), Qt::DirectConnection );
}
emit started( m_currentTrack );
if ( !m_transcode.isNull() )
{
m_transcode->clearBuffers();
m_input = io;
if ( m_audio->isPaused() )
m_audio->resume();
}
DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( m_currentTrack, DatabaseCommand_LogPlayback::Started );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
}
}
@ -228,14 +177,7 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
return false;
}
// needs to be out of the mutexlocker scope
if ( m_transcode.isNull() )
{
stop();
emit error( AudioEngine::DecodeError );
}
return !m_transcode.isNull();
return true;
}
@ -287,8 +229,6 @@ AudioEngine::playItem( PlaylistInterface* playlist, const Tomahawk::result_ptr&
{
qDebug() << Q_FUNC_INFO;
clearBuffers();
m_playlist = playlist;
m_currentTrackPlaylist = playlist;
@ -296,33 +236,6 @@ AudioEngine::playItem( PlaylistInterface* playlist, const Tomahawk::result_ptr&
}
void
AudioEngine::setStreamData( long sampleRate, int channels )
{
qDebug() << Q_FUNC_INFO << sampleRate << channels << thread();
if ( sampleRate < 44100 )
sampleRate = 44100;
m_audio->initAudio( sampleRate, channels );
if ( m_audio->startPlayback() )
{
emit started( m_currentTrack );
DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( m_currentTrack, DatabaseCommand_LogPlayback::Started );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
}
else
{
qDebug() << "Can't open device for audio output!";
stop();
emit error( AudioEngine::AudioDeviceError );
}
qDebug() << Q_FUNC_INFO << sampleRate << channels << "done";
}
void
AudioEngine::timerTriggered( unsigned int seconds )
{
@ -340,14 +253,6 @@ AudioEngine::timerTriggered( unsigned int seconds )
}
void
AudioEngine::clearBuffers()
{
QMutexLocker lock( &m_mutex );
m_audio->clearBuffers();
}
void
AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result )
{
@ -362,88 +267,3 @@ AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result )
m_currentTrack = result;
}
void
AudioEngine::run()
{
QTimer::singleShot( 0, this, SLOT( engineLoop() ) );
exec();
qDebug() << "AudioEngine event loop stopped";
}
void
AudioEngine::engineLoop()
{
qDebug() << "AudioEngine thread:" << this->thread();
loop();
}
void
AudioEngine::loop()
{
m_i++;
//if( m_i % 500 == 0 ) qDebug() << Q_FUNC_INFO << thread();
{
QMutexLocker lock( &m_mutex );
/* if ( m_i % 200 == 0 )
{
if ( !m_input.isNull() )
qDebug() << "Outer audio loop" << m_input->bytesAvailable() << m_audio->needData();
}*/
if ( m_i % 10 == 0 && m_audio->isPlaying() )
m_audio->triggerTimers();
if( !m_transcode.isNull() &&
!m_input.isNull() &&
m_input->bytesAvailable() &&
m_audio->needData() &&
!m_audio->isPaused() )
{
//if ( m_i % 50 == 0 )
// qDebug() << "Inner audio loop";
if ( m_transcode->needData() > 0 )
{
QByteArray encdata = m_input->read( m_transcode->preferredDataSize() );
m_transcode->processData( encdata, m_input->atEnd() );
}
if ( m_transcode->haveData() )
{
QByteArray rawdata = m_transcode->data();
m_audio->processData( rawdata );
}
QTimer::singleShot( 0, this, SLOT( loop() ) );
return;
}
}
unsigned int nextdelay = 50;
// are we cleanly at the end of a track, and ready for the next one?
if ( !m_input.isNull() &&
m_input->atEnd() &&
!m_input->bytesAvailable() &&
!m_audio->haveData() &&
!m_audio->isPaused() )
{
qDebug() << "Starting next track then";
loadNextTrack();
// will need data immediately:
nextdelay = 0;
}
else if ( !m_input.isNull() && !m_input->isOpen() )
{
qDebug() << "AudioEngine IODev closed. errorString:" << m_input->errorString();
loadNextTrack();
nextdelay = 0;
}
QTimer::singleShot( nextdelay, this, SLOT( loop() ) );
}

View File

@ -1,22 +1,21 @@
#ifndef AUDIOENGINE_H
#define AUDIOENGINE_H
#include <QThread>
#include <QMutex>
#include <QBuffer>
#include <QObject>
#include <Phonon/MediaObject>
#include <Phonon/AudioOutput>
#include "result.h"
#include "typedefs.h"
#include "rtaudiooutput.h"
#include "alsaplayback.h"
#include "transcodeinterface.h"
#define AUDIO_VOLUME_STEP 5
class PlaylistInterface;
class AudioEngine : public QThread
class AudioEngine : public QObject
{
Q_OBJECT
@ -26,8 +25,8 @@ public:
explicit AudioEngine();
~AudioEngine();
unsigned int volume() const { if ( m_audio ) return m_audio->volume() * 100.0; else return 0; }; // in percent
bool isPaused() const { return m_audio->isPaused(); }
unsigned int volume() const { return m_audioOutput->volume() * 100.0; } // in percent
bool isPaused() const { return m_mediaObject->state() == Phonon::PausedState; }
/* Returns the PlaylistInterface of the currently playing track. Note: This might be different to the current playlist! */
PlaylistInterface* currentTrackPlaylist() const { return m_currentTrackPlaylist; }
@ -74,36 +73,23 @@ private slots:
void loadPreviousTrack();
void loadNextTrack();
void setStreamData( long sampleRate, int channels );
void timerTriggered( unsigned int seconds );
void engineLoop();
void loop();
void setCurrentTrack( const Tomahawk::result_ptr& result );
private:
void run();
void clearBuffers();
QSharedPointer<QIODevice> m_input;
QSharedPointer<TranscodeInterface> m_transcode;
#ifdef Q_WS_X11
AlsaPlayback* m_audio;
#else
RTAudioOutput* m_audio;
#endif
Tomahawk::result_ptr m_currentTrack;
Tomahawk::result_ptr m_lastTrack;
PlaylistInterface* m_playlist;
PlaylistInterface* m_currentTrackPlaylist;
PlaylistInterface* m_queue;
QMutex m_mutex;
Phonon::MediaObject* m_mediaObject;
Phonon::AudioOutput* m_audioOutput;
unsigned int m_timeElapsed;
int m_i;
};
#endif // AUDIOENGINE_H