From ce3d37274975ea23cf9810bcfa891c3ccc679f87 Mon Sep 17 00:00:00 2001 From: dridri Date: Tue, 30 Sep 2014 01:30:44 +0200 Subject: [PATCH] More track duration calculation and seeking --- src/libtomahawk/audio/AudioEngine.cpp | 12 +++- src/libtomahawk/audio/AudioOutput.cpp | 68 +++++++++++++++++--- src/libtomahawk/audio/AudioOutput.h | 3 + src/libtomahawk/utils/MediaStream.cpp | 18 +++++- src/libtomahawk/utils/MediaStream.h | 3 + src/libtomahawk/utils/Qnr_IoDeviceStream.cpp | 2 +- 6 files changed, 93 insertions(+), 13 deletions(-) diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index 5a177c08e..1a2d0ae08 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -109,9 +109,9 @@ AudioEnginePrivate::onStateChanged( AudioOutput::AudioState newState, AudioOutpu case AudioOutput::Paused: { if ( audioOutput && currentTrack ) - {/* TODO + { qint64 duration = audioOutput->totalTime() > 0 ? audioOutput->totalTime() : currentTrack->track()->duration() * 1000; - stopped = ( duration - 1000 < audioOutput->currentTime() ); */ + stopped = ( duration - 1000 < audioOutput->currentTime() ); } else stopped = true; @@ -133,7 +133,7 @@ AudioEnginePrivate::onStateChanged( AudioOutput::AudioState newState, AudioOutpu if ( stopped && expectStop ) { expectStop = false; - tDebug( LOGVERBOSE ) << "Finding next track."; + tDebug() << "Finding next track."; if ( q_ptr->canGoNext() ) { q_ptr->loadNextTrack(); @@ -194,6 +194,7 @@ AudioEngine::AudioEngine() connect( d->audioOutput, SIGNAL( stateChanged( AudioOutput::AudioState, AudioOutput::AudioState ) ), d_func(), SLOT( onStateChanged( AudioOutput::AudioState, AudioOutput::AudioState ) ) ); connect( d->audioOutput, SIGNAL( tick( qint64 ) ), SLOT( timerTriggered( qint64 ) ) ); + connect( d->audioOutput, SIGNAL( aboutToFinish() ), SLOT( onAboutToFinish() ) ); qRegisterMetaType< AudioErrorCode >("AudioErrorCode"); qRegisterMetaType< AudioState >("AudioState"); @@ -1248,6 +1249,11 @@ AudioEngine::currentTime() const qint64 AudioEngine::currentTrackTotalTime() const { + // TODO : This is too hacky. The problem is that I don't know why + // libVLC doesn't report total duration for stream data (imem://) + if ( d_func()->currentTrack && d_func()->currentTrack->track() ) { + return d_func()->currentTrack->track()->duration() * 1000 + 1000; + } return d_func()->audioOutput->totalTime(); } diff --git a/src/libtomahawk/audio/AudioOutput.cpp b/src/libtomahawk/audio/AudioOutput.cpp index c5dcfee14..f45f573a4 100644 --- a/src/libtomahawk/audio/AudioOutput.cpp +++ b/src/libtomahawk/audio/AudioOutput.cpp @@ -18,6 +18,7 @@ * along with Tomahawk. If not, see . */ +#include "AudioEngine.h" #include "AudioOutput.h" #include "utils/Logger.h" @@ -37,6 +38,7 @@ static QString s_aeInfoIdentifier = QString( "AUDIOOUTPUT" ); +static const int ABOUT_TO_FINISH_TIME = 2000; AudioOutput* AudioOutput::s_instance = 0; @@ -55,12 +57,15 @@ AudioOutput::AudioOutput( QObject* parent ) , m_volume( 1.0 ) , m_currentTime( 0 ) , m_totalTime( 0 ) + , m_aboutToFinish( false ) , dspPluginCallback( 0 ) { tDebug() << Q_FUNC_INFO; AudioOutput::s_instance = this; currentStream = 0; + + qRegisterMetaType("AudioOutput::AudioState"); QList args; @@ -94,7 +99,7 @@ AudioOutput::AudioOutput( QObject* parent ) vlcPlayer = libvlc_media_player_new( vlcInstance ); - libvlc_event_manager_t *manager = libvlc_media_player_event_manager( vlcPlayer ); + libvlc_event_manager_t* manager = libvlc_media_player_event_manager( vlcPlayer ); libvlc_event_type_t events[] = { libvlc_MediaPlayerMediaChanged, libvlc_MediaPlayerNothingSpecial, @@ -113,7 +118,7 @@ AudioOutput::AudioOutput( QObject* parent ) libvlc_MediaPlayerPausableChanged, libvlc_MediaPlayerTitleChanged, libvlc_MediaPlayerSnapshotTaken, - libvlc_MediaPlayerLengthChanged, + //libvlc_MediaPlayerLengthChanged, libvlc_MediaPlayerVout }; const int eventCount = sizeof(events) / sizeof( *events ); @@ -142,9 +147,12 @@ void AudioOutput::setCurrentSource(MediaStream* stream) { tDebug() << Q_FUNC_INFO; - currentStream = stream; - currentState = Loading; + setState(Loading); + + currentStream = stream; + m_totalTime = 0; + m_currentTime = 0; QByteArray url; switch (stream->type()) { @@ -173,10 +181,21 @@ AudioOutput::setCurrentSource(MediaStream* stream) tDebug() << "MediaStream::Final Url:" << url; + vlcMedia = libvlc_media_new_location( vlcInstance, url.constData() ); + libvlc_event_manager_t* manager = libvlc_media_event_manager( vlcMedia ); + libvlc_event_type_t events[] = { + libvlc_MediaDurationChanged, + }; + const int eventCount = sizeof(events) / sizeof( *events ); + for ( int i = 0 ; i < eventCount ; i++ ) { + libvlc_event_attach( manager, events[ i ], &AudioOutput::vlcEventCallback, this ); + } + libvlc_media_player_set_media( vlcPlayer, vlcMedia ); + if ( stream->type() == MediaStream::Url ) { m_totalTime = libvlc_media_get_duration( vlcMedia ); } @@ -194,7 +213,8 @@ AudioOutput::setCurrentSource(MediaStream* stream) libvlc_media_add_option(vlcMedia, ":audio-filter dsp"); libvlc_media_add_option(vlcMedia, "--audio-filter dsp"); - currentState = Stopped; + m_aboutToFinish = false; + setState(Stopped); } @@ -210,8 +230,9 @@ void AudioOutput::setState( AudioState state ) { tDebug() << Q_FUNC_INFO; - emit stateChanged ( state, currentState ); + AudioState last = currentState; currentState = state; + emit stateChanged ( state, last ); } @@ -226,7 +247,20 @@ void AudioOutput::setCurrentTime( qint64 time ) { m_currentTime = time; + if ( m_totalTime <= 0 ) { + m_totalTime = AudioEngine::instance()->currentTrackTotalTime(); + } emit tick( time ); + + tDebug() << "Current time : " << m_currentTime << " / " << m_totalTime; + + if ( time < m_totalTime - ABOUT_TO_FINISH_TIME ) { + m_aboutToFinish = false; + } + if ( !m_aboutToFinish && m_totalTime > 0 && time >= m_totalTime - ABOUT_TO_FINISH_TIME ) { + m_aboutToFinish = true; + emit aboutToFinish(); + } } @@ -237,6 +271,17 @@ AudioOutput::totalTime() } +void +AudioOutput::setTotalTime( qint64 time ) +{ + if ( time > 0 ) { + m_totalTime = time; + // emit current time to refresh total time + emit tick( m_currentTime ); + } +} + + void AudioOutput::play() { @@ -367,16 +412,23 @@ AudioOutput::vlcEventCallback( const libvlc_event_t* event, void* opaque ) case libvlc_MediaPlayerSeekableChanged: //TODO, bool event->u.media_player_seekable_changed.new_seekable break; - case libvlc_MediaPlayerLengthChanged: - that->m_totalTime = event->u.media_player_length_changed.new_length; + case libvlc_MediaDurationChanged: + that->setTotalTime( event->u.media_duration_changed.new_duration ); break; + /* + case libvlc_MediaPlayerLengthChanged: + that->setTotalTime( event->u.media_player_length_changed.new_length ); + break; + */ case libvlc_MediaPlayerNothingSpecial: case libvlc_MediaPlayerOpening: case libvlc_MediaPlayerBuffering: case libvlc_MediaPlayerPlaying: case libvlc_MediaPlayerPaused: case libvlc_MediaPlayerStopped: + break; case libvlc_MediaPlayerEndReached: + that->setState(Stopped); break; case libvlc_MediaPlayerEncounteredError: // TODO emit Error diff --git a/src/libtomahawk/audio/AudioOutput.h b/src/libtomahawk/audio/AudioOutput.h index 175c4c4bb..d5610f923 100644 --- a/src/libtomahawk/audio/AudioOutput.h +++ b/src/libtomahawk/audio/AudioOutput.h @@ -68,10 +68,12 @@ public slots: signals: void stateChanged( AudioOutput::AudioState, AudioOutput::AudioState ); void tick( qint64 ); + void aboutToFinish(); private: void setState( AudioState state ); void setCurrentTime( qint64 time ); + void setTotalTime( qint64 time ); static void vlcEventCallback( const libvlc_event_t *event, void *opaque ); static void s_dspCallback( signed short* samples, int nb_channels, int nb_samples ); @@ -83,6 +85,7 @@ private: qreal m_volume; qint64 m_currentTime; qint64 m_totalTime; + bool m_aboutToFinish; void ( *dspPluginCallback ) ( signed short* samples, int nb_channels, int nb_samples ); diff --git a/src/libtomahawk/utils/MediaStream.cpp b/src/libtomahawk/utils/MediaStream.cpp index 5b7dc7ad1..ac2cee4ab 100644 --- a/src/libtomahawk/utils/MediaStream.cpp +++ b/src/libtomahawk/utils/MediaStream.cpp @@ -29,6 +29,7 @@ static QString s_aeInfoIdentifier = QString( "MEDIASTREAM" ); MediaStream::MediaStream() : m_type( Unknown ) , m_url( QUrl() ) + , m_eos( false ) , m_pos( 0 ) , m_streamSize( 0 ) { @@ -85,6 +86,15 @@ MediaStream::setStreamSize( qint64 size ) } +void +MediaStream::endOfData() +{ + tDebug() << Q_FUNC_INFO; + + m_eos = true; +} + + int MediaStream::readCallback ( void* data, const char* cookie, int64_t* dts, int64_t* pts, unsigned* flags, size_t* bufferSize, void** buffer ) { @@ -97,6 +107,10 @@ MediaStream::readCallback ( void* data, const char* cookie, int64_t* dts, int64_ MediaStream* that = static_cast < MediaStream * > ( data ); + if ( that->m_eos == true ) { + return -1; + } + *bufferSize = that->needData(buffer); return 0; } @@ -110,7 +124,9 @@ MediaStream::readDoneCallback ( void *data, const char *cookie, size_t bufferSiz Q_UNUSED(data); Q_UNUSED(cookie); Q_UNUSED(bufferSize); - delete static_cast(buffer); + +// TODO : causes segfault +// delete static_cast(buffer); return 0; } diff --git a/src/libtomahawk/utils/MediaStream.h b/src/libtomahawk/utils/MediaStream.h index 28000c4ca..b7dd67987 100644 --- a/src/libtomahawk/utils/MediaStream.h +++ b/src/libtomahawk/utils/MediaStream.h @@ -53,9 +53,12 @@ public: static int seekCallback ( void *data, const uint64_t pos ); protected: + void endOfData(); + MediaType m_type; QUrl m_url; + bool m_eos; qint64 m_pos; qint64 m_streamSize; }; diff --git a/src/libtomahawk/utils/Qnr_IoDeviceStream.cpp b/src/libtomahawk/utils/Qnr_IoDeviceStream.cpp index ed72c4463..8c80fa3c2 100644 --- a/src/libtomahawk/utils/Qnr_IoDeviceStream.cpp +++ b/src/libtomahawk/utils/Qnr_IoDeviceStream.cpp @@ -100,7 +100,7 @@ QNR_IODeviceStream::needData ( void** buffer ) if ( ( data.size() == 0 ) && m_networkReply->atEnd() && m_networkReply->isFinished() ) { // We're done. -//TODO endOfData(); + endOfData(); return 0; }