1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-06 22:26:32 +02:00

Precache next track to play when reaching end of current song

This commit is contained in:
Anton Romanov
2016-11-30 11:34:19 -08:00
parent 3b6ba36e83
commit 9a5750c6f4
7 changed files with 410 additions and 196 deletions

View File

@@ -685,7 +685,7 @@ Query::howSimilar( const Tomahawk::result_ptr& r )
qTrackname = queryTrack()->trackSortname(); qTrackname = queryTrack()->trackSortname();
} }
static const QRegExp filterOutChars = QRegExp(QString::fromUtf8("[-`´~!@#$%^&*()_—+=|:;<>«»,.?/{}\'\"\\[\\]\\\\]")); static const QRegExp filterOutChars = QRegExp(QString::fromUtf8("[-`´~!@#$%^&*\\(\\)_—+=|:;<>«»,.?/{}\'\"\\[\\]\\\\]"));
//Cleanup symbols for minor naming differences //Cleanup symbols for minor naming differences
qArtistname.remove(filterOutChars); qArtistname.remove(filterOutChars);

View File

@@ -572,10 +572,10 @@ AudioEngine::onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type )
void void
AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) AudioEngine::loadTrack( const Tomahawk::result_ptr& result, bool preload )
{ {
Q_D( AudioEngine ); Q_D( AudioEngine );
tDebug( LOGEXTRA ) << Q_FUNC_INFO << ( result.isNull() ? QString() : result->url() ); tDebug( LOGEXTRA ) << Q_FUNC_INFO << ( result.isNull() ? QString() : result->url() ) << " preload:" << preload;
if ( !d->audioOutput->isInitialized() ) if ( !d->audioOutput->isInitialized() )
@@ -589,18 +589,57 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
return; return;
} }
// We do this to stop the audio as soon as a user activated another track if (preload && d->preloadedTrack == result)
// If we don't block the audioOutput signals, the state change will trigger return;
// loading yet another track
d->audioOutput->blockSignals( true );
d->audioOutput->stop();
d->audioOutput->blockSignals( false );
setCurrentTrack( result ); if (preload)
tDebug( LOGEXTRA ) << Q_FUNC_INFO << "not preloaded yet, preloading";
if (preload)
{
setPreloadTrack( result );
}
else
{
// We do this to stop the audio as soon as a user activated another track
// If we don't block the audioOutput signals, the state change will trigger
// loading yet another track
d->audioOutput->blockSignals( true );
d->audioOutput->stop();
d->audioOutput->blockSignals( false );
setCurrentTrack( result );
if ( result == d->preloadedTrack )
{
setPreloadTrack( Tomahawk::result_ptr(nullptr) );
d->state = Loading;
emit loading( d->currentTrack );
d->audioOutput->switchToPreloadedMedia();
if ( !d->input.isNull() )
{
d->input->close();
d->input.clear();
}
d->input = d->inputPreloaded;
d->audioOutput->play();
if ( TomahawkSettings::instance()->privateListeningMode() != TomahawkSettings::FullyPrivate )
{
d->currentTrack->track()->startPlaying();
}
sendNowPlayingNotification( Tomahawk::InfoSystem::InfoNowPlaying );
return;
}
setPreloadTrack( Tomahawk::result_ptr(nullptr) );
}
ScriptJob* job = result->resolvedBy()->getStreamUrl( result ); ScriptJob* job = result->resolvedBy()->getStreamUrl( result );
connect( job, SIGNAL( done( QVariantMap ) ), SLOT( gotStreamUrl( QVariantMap ) ) ); connect( job, SIGNAL( done( QVariantMap ) ), SLOT( gotStreamUrl( QVariantMap ) ) );
job->setProperty( "result", QVariant::fromValue( result ) ); job->setProperty( "result", QVariant::fromValue( result ) );
job->setProperty( "isPreload", QVariant::fromValue(preload) );
tDebug() << "preload:" << preload << ", for result:" << result;
job->start(); job->start();
} }
@@ -611,6 +650,9 @@ AudioEngine::gotStreamUrl( const QVariantMap& data )
QString streamUrl = data[ "url" ].toString(); QString streamUrl = data[ "url" ].toString();
QVariantMap headers = data[ "headers" ].toMap(); QVariantMap headers = data[ "headers" ].toMap();
Tomahawk::result_ptr result = sender()->property( "result" ).value<result_ptr>(); Tomahawk::result_ptr result = sender()->property( "result" ).value<result_ptr>();
bool isPreload = sender()->property( "isPreload" ).value<bool>();
tDebug() << Q_FUNC_INFO << " is preload:" << isPreload << ", for result:" << result;
if ( streamUrl.isEmpty() || headers.isEmpty() || if ( streamUrl.isEmpty() || headers.isEmpty() ||
!( TomahawkUtils::isHttpResult( streamUrl ) || TomahawkUtils::isHttpsResult( streamUrl ) ) ) !( TomahawkUtils::isHttpResult( streamUrl ) || TomahawkUtils::isHttpsResult( streamUrl ) ) )
@@ -618,7 +660,7 @@ AudioEngine::gotStreamUrl( const QVariantMap& data )
// We can't supply custom headers to VLC - but prefer using its HTTP streaming due to improved seeking ability // We can't supply custom headers to VLC - but prefer using its HTTP streaming due to improved seeking ability
// Not an RTMP or HTTP-with-headers URL, get IO device // Not an RTMP or HTTP-with-headers URL, get IO device
QSharedPointer< QIODevice > sp; QSharedPointer< QIODevice > sp;
performLoadIODevice( result, streamUrl ); performLoadIODevice( result, streamUrl, isPreload );
} }
else else
{ {
@@ -654,26 +696,32 @@ AudioEngine::gotStreamUrl( const QVariantMap& data )
void void
AudioEngine::gotRedirectedStreamUrl( const Tomahawk::result_ptr& result, NetworkReply* reply ) AudioEngine::gotRedirectedStreamUrl( const Tomahawk::result_ptr& result, NetworkReply* reply )
{ {
Q_D( AudioEngine );
// std::functions cannot accept temporaries as parameters // std::functions cannot accept temporaries as parameters
QSharedPointer< QIODevice > sp ( reply->reply(), &QObject::deleteLater ); QSharedPointer< QIODevice > sp ( reply->reply(), &QObject::deleteLater );
QString url = reply->reply()->url().toString(); QString url = reply->reply()->url().toString();
reply->disconnectFromReply(); reply->disconnectFromReply();
reply->deleteLater(); reply->deleteLater();
performLoadTrack( result, url, sp ); bool isPreload = result == d->preloadedTrack;
tDebug() << Q_FUNC_INFO << " is preload:" << isPreload;
performLoadTrack( result, url, sp, isPreload );
} }
void void
AudioEngine::onPositionChanged( float new_position ) AudioEngine::onPositionChanged( float new_position )
{ {
if ( new_position >= 0.90 )
loadNextTrack(true);
// tDebug() << Q_FUNC_INFO << new_position << state(); // tDebug() << Q_FUNC_INFO << new_position << state();
emit trackPosition( new_position ); emit trackPosition( new_position );
} }
void void
AudioEngine::performLoadIODevice( const result_ptr& result, const QString& url ) AudioEngine::performLoadIODevice( const result_ptr& result, const QString& url, bool preload )
{ {
tDebug( LOGEXTRA ) << Q_FUNC_INFO << ( result.isNull() ? QString() : url ); tDebug( LOGEXTRA ) << Q_FUNC_INFO << ( result.isNull() ? QString() : url );
@@ -683,37 +731,39 @@ AudioEngine::performLoadIODevice( const result_ptr& result, const QString& url )
std::function< void ( const QString, QSharedPointer< QIODevice > ) > callback = std::function< void ( const QString, QSharedPointer< QIODevice > ) > callback =
std::bind( &AudioEngine::performLoadTrack, this, result, std::bind( &AudioEngine::performLoadTrack, this, result,
std::placeholders::_1, std::placeholders::_1,
std::placeholders::_2 ); std::placeholders::_2,
preload );
Tomahawk::UrlHandler::getIODeviceForUrl( result, url, callback ); Tomahawk::UrlHandler::getIODeviceForUrl( result, url, callback );
} }
else else
{ {
QSharedPointer< QIODevice > io; QSharedPointer< QIODevice > io;
performLoadTrack( result, url, io ); performLoadTrack( result, url, io, preload );
} }
} }
void void
AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString& url, QSharedPointer< QIODevice > io ) AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString& url, QSharedPointer< QIODevice > io, bool preload )
{ {
if ( QThread::currentThread() != thread() ) if ( QThread::currentThread() != thread() )
{ {
QMetaObject::invokeMethod( this, "performLoadTrack", Qt::QueuedConnection, QMetaObject::invokeMethod( this, "performLoadTrack", Qt::QueuedConnection,
Q_ARG( const Tomahawk::result_ptr, result ), Q_ARG( const Tomahawk::result_ptr, result ),
Q_ARG( const QString, url ), Q_ARG( const QString, url ),
Q_ARG( QSharedPointer< QIODevice >, io ) Q_ARG( QSharedPointer< QIODevice >, io ),
Q_ARG( bool, preload )
); );
return; return;
} }
Q_D( AudioEngine ); Q_D( AudioEngine );
if ( currentTrack() != result ) if ( !preload && currentTrack() != result )
{ {
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Track loaded too late, skip."; tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Track loaded too late, skip.";
return; return;
} }
tDebug( LOGEXTRA ) << Q_FUNC_INFO << ( result.isNull() ? QString() : result->url() ); tDebug( LOGEXTRA ) << Q_FUNC_INFO << ( result.isNull() ? QString() : result->url() ) << preload;
QSharedPointer< QIODevice > ioToKeep = io; QSharedPointer< QIODevice > ioToKeep = io;
bool err = false; bool err = false;
@@ -727,9 +777,16 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString&
if ( !err ) if ( !err )
{ {
tLog() << Q_FUNC_INFO << "Starting new song:" << url; if (preload)
d->state = Loading; {
emit loading( d->currentTrack ); tLog() << Q_FUNC_INFO << "Preloading new song:" << url;
}
else
{
tLog() << Q_FUNC_INFO << "Starting new song:" << url;
d->state = Loading;
emit loading( d->currentTrack );
}
if ( !TomahawkUtils::isLocalResult( url ) if ( !TomahawkUtils::isLocalResult( url )
&& !( TomahawkUtils::isHttpResult( url ) && io.isNull() ) && !( TomahawkUtils::isHttpResult( url ) && io.isNull() )
@@ -738,18 +795,18 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString&
QSharedPointer<QNetworkReply> qnr = io.objectCast<QNetworkReply>(); QSharedPointer<QNetworkReply> qnr = io.objectCast<QNetworkReply>();
if ( !qnr.isNull() ) if ( !qnr.isNull() )
{ {
d->audioOutput->setCurrentSource( new QNR_IODeviceStream( qnr, this ) ); d->audioOutput->setCurrentSource( new QNR_IODeviceStream( qnr, this ), preload );
// We keep track of the QNetworkReply in QNR_IODeviceStream // We keep track of the QNetworkReply in QNR_IODeviceStream
// and AudioOutput handles the deletion of the // and AudioOutput handles the deletion of the
// QNR_IODeviceStream object // QNR_IODeviceStream object
ioToKeep.clear(); ioToKeep.clear();
d->audioOutput->setAutoDelete( true ); d->audioOutput->setAutoDelete( true, preload );
} }
else else
{ {
d->audioOutput->setCurrentSource( io.data() ); d->audioOutput->setCurrentSource( io.data(), preload);
// We handle the deletion via tracking in d->input // We handle the deletion via tracking in d->input
d->audioOutput->setAutoDelete( false ); d->audioOutput->setAutoDelete( false, preload);
} }
} }
else else
@@ -768,7 +825,7 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString&
} }
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Passing to VLC:" << furl; tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Passing to VLC:" << furl;
d->audioOutput->setCurrentSource( furl ); d->audioOutput->setCurrentSource( furl, preload );
} }
else else
{ {
@@ -777,26 +834,37 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString&
furl = furl.right( furl.length() - 7 ); furl = furl.right( furl.length() - 7 );
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Passing to VLC:" << QUrl::fromLocalFile( furl ); tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Passing to VLC:" << QUrl::fromLocalFile( furl );
d->audioOutput->setCurrentSource( QUrl::fromLocalFile( furl ) ); d->audioOutput->setCurrentSource( QUrl::fromLocalFile( furl ), preload );
} }
d->audioOutput->setAutoDelete( true ); d->audioOutput->setAutoDelete( true, preload );
} }
if ( !d->input.isNull() ) if ( preload ) {
if ( !d->inputPreloaded.isNull() )
{
d->inputPreloaded->close();
d->inputPreloaded.clear();
}
d->inputPreloaded = ioToKeep;
}
else
{ {
d->input->close(); if ( !d->input.isNull() )
d->input.clear(); {
} d->input->close();
d->input = ioToKeep; d->input.clear();
d->audioOutput->play(); }
d->input = ioToKeep;
d->audioOutput->play();
if ( TomahawkSettings::instance()->privateListeningMode() != TomahawkSettings::FullyPrivate ) if ( TomahawkSettings::instance()->privateListeningMode() != TomahawkSettings::FullyPrivate )
{ {
d->currentTrack->track()->startPlaying(); d->currentTrack->track()->startPlaying();
} }
sendNowPlayingNotification( Tomahawk::InfoSystem::InfoNowPlaying ); sendNowPlayingNotification( Tomahawk::InfoSystem::InfoNowPlaying );
}
} }
} }
@@ -806,7 +874,10 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString&
return; return;
} }
d->waitingOnNewTrack = false; if ( !preload )
{
d->waitingOnNewTrack = false;
}
return; return;
} }
@@ -838,18 +909,19 @@ AudioEngine::loadPreviousTrack()
} }
if ( result ) if ( result )
loadTrack( result ); loadTrack( result, false );
else else
stop(); stop();
} }
void void
AudioEngine::loadNextTrack() AudioEngine::loadNextTrack( bool preload )
{ {
if ( QThread::currentThread() != thread() ) if ( QThread::currentThread() != thread() )
{ {
QMetaObject::invokeMethod( this, "loadNextTrack", Qt::QueuedConnection ); QMetaObject::invokeMethod( this, "loadNextTrack", Qt::QueuedConnection,
Q_ARG( bool, preload ));
return; return;
} }
@@ -863,8 +935,11 @@ AudioEngine::loadNextTrack()
{ {
if ( d->stopAfterTrack->track()->equals( d->currentTrack->track() ) ) if ( d->stopAfterTrack->track()->equals( d->currentTrack->track() ) )
{ {
d->stopAfterTrack.clear(); if ( !preload )
stop(); {
d->stopAfterTrack.clear();
stop();
}
return; return;
} }
} }
@@ -882,17 +957,24 @@ AudioEngine::loadNextTrack()
if ( d->playlist.data()->nextResult() ) if ( d->playlist.data()->nextResult() )
{ {
result = d->playlist.data()->setSiblingResult( 1 ); if ( preload )
setCurrentTrackPlaylist( d->playlist ); {
result = d->playlist.data()->nextResult();
}
else
{
result = d->playlist.data()->setSiblingResult( 1 );
setCurrentTrackPlaylist( d->playlist );
}
} }
} }
if ( result ) if ( result )
{ {
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Got next item, loading track"; tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Got next item, loading track, preload:" << preload;
loadTrack( result ); loadTrack( result, preload );
} }
else else if ( !preload )
{ {
if ( !d->playlist.isNull() && d->playlist.data()->retryMode() == Tomahawk::PlaylistModes::Retry ) if ( !d->playlist.isNull() && d->playlist.data()->retryMode() == Tomahawk::PlaylistModes::Retry )
d->waitingOnNewTrack = true; d->waitingOnNewTrack = true;
@@ -961,7 +1043,7 @@ AudioEngine::playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk:
if ( result ) if ( result )
{ {
loadTrack( result ); loadTrack( result, false );
} }
else if ( !d->playlist.isNull() && d->playlist.data()->retryMode() == PlaylistModes::Retry ) else if ( !d->playlist.isNull() && d->playlist.data()->retryMode() == PlaylistModes::Retry )
{ {
@@ -1236,6 +1318,14 @@ AudioEngine::setStopAfterTrack( const query_ptr& query )
} }
void
AudioEngine::setPreloadTrack( const Tomahawk::result_ptr& result )
{
Q_D( AudioEngine );
d->preloadedTrack = result;
}
void void
AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result ) AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result )
{ {
@@ -1262,7 +1352,6 @@ AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result )
} }
} }
void void
AudioEngine::setState( AudioState state ) AudioEngine::setState( AudioState state )
{ {

View File

@@ -135,10 +135,10 @@ public slots:
void toggleMute(); void toggleMute();
void play( const QUrl& url ); void play( const QUrl& url );
void playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk::result_ptr& result, const Tomahawk::query_ptr& fromQuery = Tomahawk::query_ptr() ); void playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk::result_ptr& result, const Tomahawk::query_ptr& fromQuery = Tomahawk::query_ptr());
void playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk::query_ptr& query ); void playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk::query_ptr& query);
void playItem( const Tomahawk::artist_ptr& artist ); void playItem( const Tomahawk::artist_ptr& artist);
void playItem( const Tomahawk::album_ptr& album ); void playItem( const Tomahawk::album_ptr& album);
void playPlaylistInterface( const Tomahawk::playlistinterface_ptr& playlist ); void playPlaylistInterface( const Tomahawk::playlistinterface_ptr& playlist );
void setPlaylist( Tomahawk::playlistinterface_ptr playlist ); void setPlaylist( Tomahawk::playlistinterface_ptr playlist );
void setQueue( const Tomahawk::playlistinterface_ptr& queue ); void setQueue( const Tomahawk::playlistinterface_ptr& queue );
@@ -182,21 +182,22 @@ signals:
void error( AudioEngine::AudioErrorCode errorCode ); void error( AudioEngine::AudioErrorCode errorCode );
private slots: private slots:
void loadTrack( const Tomahawk::result_ptr& result ); //async! void loadTrack( const Tomahawk::result_ptr& result, bool preload ); //async!
void gotStreamUrl( const QVariantMap& data ); void gotStreamUrl( const QVariantMap& data );
void gotRedirectedStreamUrl( const Tomahawk::result_ptr& result, NetworkReply* reply ); void gotRedirectedStreamUrl( const Tomahawk::result_ptr& result, NetworkReply* reply );
void performLoadIODevice( const Tomahawk::result_ptr& result, const QString& url ); //only call from loadTrack kthxbi void performLoadIODevice( const Tomahawk::result_ptr& result, const QString& url, bool preload ); //only call from loadTrack kthxbi
void performLoadTrack( const Tomahawk::result_ptr result, const QString& url, QSharedPointer< QIODevice > io ); //only call from loadTrack or performLoadIODevice kthxbi void performLoadTrack( const Tomahawk::result_ptr result, const QString& url, QSharedPointer< QIODevice > io, bool preload ); //only call from loadTrack or performLoadIODevice kthxbi
void loadPreviousTrack(); void loadPreviousTrack();
void loadNextTrack(); void loadNextTrack(bool preload = false);
void onVolumeChanged( qreal volume ); void onVolumeChanged( qreal volume );
void timerTriggered( qint64 time ); void timerTriggered( qint64 time );
void onPositionChanged( float new_position ); void onPositionChanged( float new_position );
void setCurrentTrack( const Tomahawk::result_ptr& result ); void setCurrentTrack( const Tomahawk::result_ptr& result );
void setPreloadTrack( const Tomahawk::result_ptr& result );
void onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type ); void onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type );
void onPlaylistNextTrackAvailable(); void onPlaylistNextTrackAvailable();

View File

@@ -28,9 +28,11 @@ public slots:
private: private:
QSharedPointer<QIODevice> input; QSharedPointer<QIODevice> input;
QSharedPointer<QIODevice> inputPreloaded;
Tomahawk::query_ptr stopAfterTrack; Tomahawk::query_ptr stopAfterTrack;
Tomahawk::result_ptr currentTrack; Tomahawk::result_ptr currentTrack;
Tomahawk::result_ptr preloadedTrack;
Tomahawk::playlistinterface_ptr playlist; Tomahawk::playlistinterface_ptr playlist;
Tomahawk::playlistinterface_ptr currentTrackPlaylist; Tomahawk::playlistinterface_ptr currentTrackPlaylist;
Tomahawk::playlistinterface_ptr queue; Tomahawk::playlistinterface_ptr queue;

View File

@@ -56,9 +56,11 @@ AudioOutput::AudioOutput( QObject* parent )
: QObject( parent ) : QObject( parent )
, m_currentState( Stopped ) , m_currentState( Stopped )
, m_currentStream( nullptr ) , m_currentStream( nullptr )
, m_preloadedStream( nullptr )
, m_seekable( true ) , m_seekable( true )
, m_muted( false ) , m_muted( false )
, m_autoDelete( true ) , m_autoDelete( true )
, m_preloadedAutoDelete( true )
, m_volume( 1.0 ) , m_volume( 1.0 )
, m_currentTime( 0 ) , m_currentTime( 0 )
, m_totalTime( 0 ) , m_totalTime( 0 )
@@ -68,6 +70,8 @@ AudioOutput::AudioOutput( QObject* parent )
, m_vlcInstance( nullptr ) , m_vlcInstance( nullptr )
, m_vlcPlayer( nullptr ) , m_vlcPlayer( nullptr )
, m_vlcMedia( nullptr ) , m_vlcMedia( nullptr )
, m_vlcPreloadedPlayer( nullptr )
, m_vlcPreloadedMedia( nullptr )
{ {
tDebug() << Q_FUNC_INFO; tDebug() << Q_FUNC_INFO;
@@ -123,37 +127,46 @@ AudioOutput::AudioOutput( QObject* parent )
#endif #endif
m_vlcPlayer = libvlc_media_player_new( m_vlcInstance ); m_vlcPlayer = libvlc_media_player_new( m_vlcInstance );
libvlc_event_manager_t* manager = libvlc_media_player_event_manager( m_vlcPlayer ); m_vlcPreloadedPlayer = libvlc_media_player_new( m_vlcInstance );
libvlc_event_type_t events[] = {
libvlc_MediaPlayerMediaChanged, for( auto player : { m_vlcPlayer, m_vlcPreloadedPlayer } )
libvlc_MediaPlayerNothingSpecial,
libvlc_MediaPlayerOpening,
libvlc_MediaPlayerBuffering,
libvlc_MediaPlayerPlaying,
libvlc_MediaPlayerPaused,
libvlc_MediaPlayerStopped,
libvlc_MediaPlayerForward,
libvlc_MediaPlayerBackward,
libvlc_MediaPlayerEndReached,
libvlc_MediaPlayerEncounteredError,
libvlc_MediaPlayerTimeChanged,
libvlc_MediaPlayerPositionChanged,
libvlc_MediaPlayerSeekableChanged,
libvlc_MediaPlayerPausableChanged,
libvlc_MediaPlayerTitleChanged,
libvlc_MediaPlayerSnapshotTaken,
//libvlc_MediaPlayerLengthChanged,
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 2, 0))
libvlc_MediaPlayerAudioVolume,
libvlc_MediaPlayerMuted,
libvlc_MediaPlayerUnmuted,
#endif
libvlc_MediaPlayerVout
};
const int eventCount = sizeof(events) / sizeof( *events );
for ( int i = 0; i < eventCount; i++ )
{ {
libvlc_event_attach( manager, events[ i ], &AudioOutput::vlcEventCallback, this ); libvlc_audio_set_mute( player, 0 );
{
libvlc_event_manager_t* current_manager = libvlc_media_player_event_manager( player );
libvlc_event_manager_t* new_manager = libvlc_media_player_event_manager( player );
static libvlc_event_type_t events[] = {
libvlc_MediaPlayerMediaChanged,
libvlc_MediaPlayerNothingSpecial,
libvlc_MediaPlayerOpening,
libvlc_MediaPlayerBuffering,
libvlc_MediaPlayerPlaying,
libvlc_MediaPlayerPaused,
libvlc_MediaPlayerStopped,
libvlc_MediaPlayerForward,
libvlc_MediaPlayerBackward,
libvlc_MediaPlayerEndReached,
libvlc_MediaPlayerEncounteredError,
libvlc_MediaPlayerTimeChanged,
libvlc_MediaPlayerPositionChanged,
libvlc_MediaPlayerSeekableChanged,
libvlc_MediaPlayerPausableChanged,
libvlc_MediaPlayerTitleChanged,
libvlc_MediaPlayerSnapshotTaken,
//libvlc_MediaPlayerLengthChanged,
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 2, 0))
libvlc_MediaPlayerAudioVolume,
libvlc_MediaPlayerMuted,
libvlc_MediaPlayerUnmuted,
#endif
libvlc_MediaPlayerVout
};
const int eventCount = sizeof(events) / sizeof( *events );
for ( int i = 0; i < eventCount; i++ )
{
libvlc_event_attach( new_manager, events[ i ], &AudioOutput::vlcEventCallback, this );
}
}
} }
// HACK: play silent ogg file and set volume on that to workaround vlc not allowing to set volume before a file is played // HACK: play silent ogg file and set volume on that to workaround vlc not allowing to set volume before a file is played
@@ -161,7 +174,9 @@ AudioOutput::AudioOutput( QObject* parent )
Q_ASSERT( m_silenceFile.exists() ); Q_ASSERT( m_silenceFile.exists() );
Q_ASSERT( m_silenceFile.open( QIODevice::ReadOnly ) ); Q_ASSERT( m_silenceFile.open( QIODevice::ReadOnly ) );
setCurrentSource( new MediaStream( &m_silenceFile, true ) ); setCurrentSource( new MediaStream( &m_silenceFile, true ), false );
setCurrentSource( new MediaStream( &m_silenceFile, true ), true );
libvlc_media_player_play( m_vlcPlayer ); libvlc_media_player_play( m_vlcPlayer );
#if QT_VERSION >= QT_VERSION_CHECK(5,4,0) #if QT_VERSION >= QT_VERSION_CHECK(5,4,0)
@@ -169,24 +184,71 @@ AudioOutput::AudioOutput( QObject* parent )
QTimer::singleShot( 15000, [&]() QTimer::singleShot( 15000, [&]()
{ {
if ( !m_initialized ) { if ( !m_initialized ) {
m_initialized = true; m_initialized = 2;
emit initialized(); emit initialized();
} }
} ); } );
#endif #endif
} }
void AudioOutput::switchToPreloadedMedia( void )
{
//Swap
auto tempPlayer = m_vlcPreloadedPlayer;
m_vlcPreloadedPlayer = m_vlcPlayer;
m_vlcPlayer = tempPlayer;
libvlc_media_player_stop( m_vlcPreloadedPlayer );
if ( m_vlcMedia != nullptr )
{
libvlc_media_release( m_vlcMedia );
}
//Now Media
{
if ( m_autoDelete && m_currentStream != nullptr )
{
delete m_currentStream;
}
m_vlcMedia = m_vlcPreloadedMedia;
m_vlcPreloadedMedia = nullptr;
m_currentStream = m_preloadedStream;
m_preloadedStream = nullptr;
m_autoDelete = m_preloadedAutoDelete;
m_totalTime = libvlc_media_get_duration( m_vlcMedia );
m_currentTime = 0;
m_justSeeked = false;
m_seekable = true;
}
libvlc_media_player_set_position( m_vlcPlayer, 0.0 );
}
AudioOutput::~AudioOutput() AudioOutput::~AudioOutput()
{ {
tDebug() << Q_FUNC_INFO; tDebug() << Q_FUNC_INFO;
if ( m_vlcPreloadedPlayer != nullptr )
{
libvlc_media_player_stop( m_vlcPreloadedPlayer );
libvlc_media_player_release( m_vlcPreloadedPlayer );
m_vlcPreloadedPlayer = nullptr;
}
if ( m_vlcPlayer != nullptr ) if ( m_vlcPlayer != nullptr )
{ {
libvlc_media_player_stop( m_vlcPlayer ); libvlc_media_player_stop( m_vlcPlayer );
libvlc_media_player_release( m_vlcPlayer ); libvlc_media_player_release( m_vlcPlayer );
m_vlcPlayer = nullptr; m_vlcPlayer = nullptr;
} }
if ( m_vlcPreloadedMedia != nullptr )
{
libvlc_media_release( m_vlcPreloadedMedia );
m_vlcPreloadedMedia = nullptr;
}
if ( m_vlcMedia != nullptr ) if ( m_vlcMedia != nullptr )
{ {
libvlc_media_release( m_vlcMedia ); libvlc_media_release( m_vlcMedia );
@@ -208,11 +270,19 @@ AudioOutput::onInitVlcEvent( const libvlc_event_t* event )
setVolume( volume() ); setVolume( volume() );
setMuted( isMuted() ); setMuted( isMuted() );
m_initialized = true; m_initialized ++;
m_silenceFile.close();
tDebug() << Q_FUNC_INFO << "Init OK"; tDebug() << Q_FUNC_INFO << "Init OK";
emit initialized(); if (m_initialized >=2)
{
m_silenceFile.close();
emit initialized();
}
else
{
switchToPreloadedMedia();
libvlc_media_player_play( m_vlcPlayer );
}
break; break;
default: default:
@@ -222,23 +292,26 @@ AudioOutput::onInitVlcEvent( const libvlc_event_t* event )
void void
AudioOutput::setAutoDelete( bool ad ) AudioOutput::setAutoDelete( bool ad, bool preload )
{ {
m_autoDelete = ad; if (preload)
m_preloadedAutoDelete = ad;
else
m_autoDelete = ad;
} }
void void
AudioOutput::setCurrentSource( const QUrl& stream ) AudioOutput::setCurrentSource( const QUrl& stream, bool preload )
{ {
setCurrentSource( new MediaStream( stream ) ); setCurrentSource( new MediaStream( stream ), preload );
} }
void void
AudioOutput::setCurrentSource( QIODevice* stream ) AudioOutput::setCurrentSource( QIODevice* stream, bool preload )
{ {
setCurrentSource( new MediaStream( stream ) ); setCurrentSource( new MediaStream( stream ), preload );
} }
@@ -258,29 +331,24 @@ readDoneCallback( void* data, const char* cookie, size_t bufferSize, void* buffe
void void
AudioOutput::setCurrentSource( MediaStream* stream ) AudioOutput::setCurrentSource( MediaStream* stream, bool preload )
{ {
tDebug() << Q_FUNC_INFO; tDebug() << Q_FUNC_INFO << ", preload = " << preload;
setState( Loading ); if ( !preload )
setState( Loading );
if ( m_vlcMedia != nullptr ) if ( m_vlcPreloadedMedia ) {
{ libvlc_media_player_stop( m_vlcPreloadedPlayer );
// Ensure playback is stopped, then release media libvlc_media_release( m_vlcPreloadedMedia );
libvlc_media_player_stop( m_vlcPlayer ); m_vlcPreloadedMedia = nullptr;
libvlc_media_release( m_vlcMedia );
m_vlcMedia = nullptr;
} }
if ( m_autoDelete && m_currentStream != nullptr ) if ( m_preloadedAutoDelete && m_preloadedStream != nullptr )
{ {
delete m_currentStream; delete m_preloadedStream;
} }
m_currentStream = stream; m_preloadedStream = stream;
m_totalTime = 0;
m_currentTime = 0;
m_justSeeked = false;
m_seekable = true;
QByteArray url; QByteArray url;
switch ( stream->type() ) switch ( stream->type() )
@@ -314,23 +382,19 @@ AudioOutput::setCurrentSource( MediaStream* stream )
tDebug() << Q_FUNC_INFO << "MediaStream::Final Url:" << url; tDebug() << Q_FUNC_INFO << "MediaStream::Final Url:" << url;
m_vlcMedia = libvlc_media_new_location( m_vlcInstance, url.constData() ); m_vlcPreloadedMedia = libvlc_media_new_location( m_vlcInstance, url.constData() );
if ( stream->type() == MediaStream::Url ) if ( stream->type() == MediaStream::Stream || stream->type() == MediaStream::IODevice )
{
m_totalTime = libvlc_media_get_duration( m_vlcMedia );
}
else if ( stream->type() == MediaStream::Stream || stream->type() == MediaStream::IODevice )
{ {
QString tempString; QString tempString;
libvlc_media_add_option_flag(m_vlcMedia, "imem-cat=4", libvlc_media_option_trusted); libvlc_media_add_option_flag(m_vlcPreloadedMedia, "imem-cat=4", libvlc_media_option_trusted);
tempString = QString( "imem-data=%1" ).arg( (uintptr_t)stream ); tempString = QString( "imem-data=%1" ).arg( (uintptr_t)stream );
libvlc_media_add_option_flag(m_vlcMedia, tempString.toLatin1().constData(), libvlc_media_option_trusted); libvlc_media_add_option_flag(m_vlcPreloadedMedia, tempString.toLatin1().constData(), libvlc_media_option_trusted);
tempString = QString( "imem-get=%1" ).arg( (uintptr_t)&readCallback ); tempString = QString( "imem-get=%1" ).arg( (uintptr_t)&readCallback );
libvlc_media_add_option_flag(m_vlcMedia, tempString.toLatin1().constData(), libvlc_media_option_trusted); libvlc_media_add_option_flag(m_vlcPreloadedMedia, tempString.toLatin1().constData(), libvlc_media_option_trusted);
tempString = QString( "imem-release=%1" ).arg( (uintptr_t)&readDoneCallback ); tempString = QString( "imem-release=%1" ).arg( (uintptr_t)&readDoneCallback );
libvlc_media_add_option_flag(m_vlcMedia, tempString.toLatin1().constData(), libvlc_media_option_trusted); libvlc_media_add_option_flag(m_vlcPreloadedMedia, tempString.toLatin1().constData(), libvlc_media_option_trusted);
tempString = QString( "imem-seek=%1" ).arg( (uintptr_t)&MediaStream::seekCallback ); tempString = QString( "imem-seek=%1" ).arg( (uintptr_t)&MediaStream::seekCallback );
libvlc_media_add_option_flag(m_vlcMedia, tempString.toLatin1().constData(), libvlc_media_option_trusted); libvlc_media_add_option_flag(m_vlcPreloadedMedia, tempString.toLatin1().constData(), libvlc_media_option_trusted);
} }
if ( qApp->arguments().contains( "--chromecast-ip" ) ) if ( qApp->arguments().contains( "--chromecast-ip" ) )
{ {
@@ -346,7 +410,7 @@ AudioOutput::setCurrentSource( MediaStream* stream )
{ {
QString castIP = qApp->arguments().at( qApp->arguments().indexOf( "--chromecast-ip" ) + 1 ); QString castIP = qApp->arguments().at( qApp->arguments().indexOf( "--chromecast-ip" ) + 1 );
QString sout( ":sout=#transcode{vcodec=none,acodec=vorb,ab=320,channels=2,samplerate=44100}:chromecast{ip=%1,mux=webm}" ); QString sout( ":sout=#transcode{vcodec=none,acodec=vorb,ab=320,channels=2,samplerate=44100}:chromecast{ip=%1,mux=webm}" );
libvlc_media_add_option( m_vlcMedia, sout.arg( castIP ).toLatin1().constData() ); libvlc_media_add_option( m_vlcPreloadedMedia, sout.arg( castIP ).toLatin1().constData() );
} }
else else
{ {
@@ -354,8 +418,8 @@ AudioOutput::setCurrentSource( MediaStream* stream )
} }
} }
libvlc_event_manager_t* manager = libvlc_media_event_manager( m_vlcMedia ); libvlc_event_manager_t* manager = libvlc_media_event_manager( m_vlcPreloadedMedia );
libvlc_event_type_t events[] = { static libvlc_event_type_t events[] = {
libvlc_MediaDurationChanged, libvlc_MediaDurationChanged,
}; };
const int eventCount = sizeof(events) / sizeof( *events ); const int eventCount = sizeof(events) / sizeof( *events );
@@ -364,7 +428,13 @@ AudioOutput::setCurrentSource( MediaStream* stream )
libvlc_event_attach( manager, events[ i ], &AudioOutput::vlcEventCallback, this ); libvlc_event_attach( manager, events[ i ], &AudioOutput::vlcEventCallback, this );
} }
libvlc_media_player_set_media( m_vlcPlayer, m_vlcMedia ); libvlc_media_player_set_media( m_vlcPreloadedPlayer, m_vlcPreloadedMedia );
libvlc_audio_set_volume( m_vlcPreloadedPlayer, 0.0 );
libvlc_media_player_play( m_vlcPreloadedPlayer );
if ( !preload )
switchToPreloadedMedia();
// setState( Stopped ); // setState( Stopped );
} }
@@ -373,7 +443,7 @@ AudioOutput::setCurrentSource( MediaStream* stream )
bool bool
AudioOutput::isInitialized() const AudioOutput::isInitialized() const
{ {
return m_initialized; return m_initialized > 1;
} }
@@ -526,7 +596,7 @@ AudioOutput::seek( qint64 milliseconds )
bool bool
AudioOutput::isSeekable() const AudioOutput::isSeekable() const
{ {
// tDebug() << Q_FUNC_INFO << m_seekable << m_havePosition << m_totalTime << libvlc_media_player_is_seekable( m_vlcPlayer ); tDebug() << Q_FUNC_INFO << m_seekable << m_havePosition << m_totalTime << libvlc_media_player_is_seekable( m_vlcPlayer );
return m_havePosition || (libvlc_media_player_is_seekable( m_vlcPlayer ) && m_totalTime > 0 ); return m_havePosition || (libvlc_media_player_is_seekable( m_vlcPlayer ) && m_totalTime > 0 );
} }
@@ -576,64 +646,107 @@ AudioOutput::setVolume( qreal vol )
void void
AudioOutput::onVlcEvent( const libvlc_event_t* event ) AudioOutput::onVlcEvent( const libvlc_event_t* event )
{ {
switch ( event->type ) if ( event->p_obj == m_vlcPlayer || event->p_obj == m_vlcMedia )
{ {
case libvlc_MediaPlayerTimeChanged: switch ( event->type )
setCurrentTime( event->u.media_player_time_changed.new_time ); {
break; case libvlc_MediaPlayerTimeChanged:
case libvlc_MediaPlayerPositionChanged: setCurrentTime( event->u.media_player_time_changed.new_time );
setCurrentPosition( event->u.media_player_position_changed.new_position ); break;
break; case libvlc_MediaPlayerPositionChanged:
case libvlc_MediaPlayerSeekableChanged: setCurrentPosition( event->u.media_player_position_changed.new_position );
// tDebug() << Q_FUNC_INFO << " : seekable changed : " << event->u.media_player_seekable_changed.new_seekable; break;
break; case libvlc_MediaPlayerSeekableChanged:
case libvlc_MediaDurationChanged: // tDebug() << Q_FUNC_INFO << " : seekable changed : " << event->u.media_player_seekable_changed.new_seekable;
setTotalTime( event->u.media_duration_changed.new_duration ); break;
break; case libvlc_MediaDurationChanged:
case libvlc_MediaPlayerLengthChanged: setTotalTime( event->u.media_duration_changed.new_duration );
// tDebug() << Q_FUNC_INFO << " : length changed : " << event->u.media_player_length_changed.new_length; break;
break; case libvlc_MediaPlayerLengthChanged:
case libvlc_MediaPlayerPlaying: // tDebug() << Q_FUNC_INFO << " : length changed : " << event->u.media_player_length_changed.new_length;
setState( Playing ); break;
break; case libvlc_MediaPlayerPlaying:
case libvlc_MediaPlayerPaused: setState( Playing );
setState( Paused ); break;
break; case libvlc_MediaPlayerPaused:
case libvlc_MediaPlayerEndReached: setState( Paused );
setState( Stopped ); break;
break; case libvlc_MediaPlayerEndReached:
case libvlc_MediaPlayerEncounteredError: setState( Stopped );
tDebug() << Q_FUNC_INFO << "LibVLC error: MediaPlayerEncounteredError. Stopping"; break;
// Don't call stop() here - it will deadlock libvlc case libvlc_MediaPlayerEncounteredError:
setState( Error ); tDebug() << Q_FUNC_INFO << "LibVLC error: MediaPlayerEncounteredError. Stopping";
break; // Don't call stop() here - it will deadlock libvlc
setState( Error );
break;
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 2, 0)) #if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 2, 0))
case libvlc_MediaPlayerAudioVolume: case libvlc_MediaPlayerAudioVolume:
m_volume = event->u.media_player_audio_volume.volume; m_volume = event->u.media_player_audio_volume.volume;
emit volumeChanged( volume() ); tDebug() << Q_FUNC_INFO << "Got signal in current player that volume changed to:" << m_volume;
break; emit volumeChanged( volume() );
case libvlc_MediaPlayerMuted: break;
m_muted = true; case libvlc_MediaPlayerMuted:
emit mutedChanged( true ); m_muted = true;
break; emit mutedChanged( true );
case libvlc_MediaPlayerUnmuted: break;
m_muted = false; case libvlc_MediaPlayerUnmuted:
emit mutedChanged( false ); m_muted = false;
break; emit mutedChanged( false );
break;
#endif #endif
case libvlc_MediaPlayerNothingSpecial: case libvlc_MediaPlayerNothingSpecial:
case libvlc_MediaPlayerOpening: case libvlc_MediaPlayerOpening:
case libvlc_MediaPlayerBuffering: case libvlc_MediaPlayerBuffering:
case libvlc_MediaPlayerStopped: case libvlc_MediaPlayerStopped:
case libvlc_MediaPlayerVout: case libvlc_MediaPlayerVout:
case libvlc_MediaPlayerMediaChanged: case libvlc_MediaPlayerMediaChanged:
case libvlc_MediaPlayerForward: case libvlc_MediaPlayerForward:
case libvlc_MediaPlayerBackward: case libvlc_MediaPlayerBackward:
case libvlc_MediaPlayerPausableChanged: case libvlc_MediaPlayerPausableChanged:
case libvlc_MediaPlayerTitleChanged: case libvlc_MediaPlayerTitleChanged:
case libvlc_MediaPlayerSnapshotTaken: case libvlc_MediaPlayerSnapshotTaken:
default: default:
break; break;
}
}
else
{
tDebug() << "Event for preloaded: " << libvlc_event_type_name(event->type);
switch ( event->type )
{
case libvlc_MediaPlayerPausableChanged:
case libvlc_MediaPlayerPlaying:
case libvlc_MediaPlayerMediaChanged:
case libvlc_MediaPlayerTitleChanged:
case libvlc_MediaPlayerSeekableChanged:
case libvlc_MediaDurationChanged:
case libvlc_MediaPlayerPositionChanged:
case libvlc_MediaPlayerPaused:
case libvlc_MediaPlayerBuffering:
libvlc_media_player_set_pause( m_vlcPreloadedPlayer, 1 );
libvlc_audio_set_volume( m_vlcPreloadedPlayer, 0.0 );
libvlc_media_player_set_position( m_vlcPreloadedPlayer, 0.0 );
break;
case libvlc_MediaPlayerTimeChanged:
case libvlc_MediaPlayerLengthChanged:
case libvlc_MediaPlayerOpening:
case libvlc_MediaPlayerEndReached:
case libvlc_MediaPlayerEncounteredError:
//TODO
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 2, 0))
case libvlc_MediaPlayerAudioVolume:
case libvlc_MediaPlayerMuted:
case libvlc_MediaPlayerUnmuted:
#endif
case libvlc_MediaPlayerNothingSpecial:
case libvlc_MediaPlayerStopped:
case libvlc_MediaPlayerVout:
case libvlc_MediaPlayerForward:
case libvlc_MediaPlayerBackward:
case libvlc_MediaPlayerSnapshotTaken:
default:
break;
}
} }
} }

View File

@@ -49,9 +49,10 @@ public:
bool isInitialized() const; bool isInitialized() const;
AudioState state() const; AudioState state() const;
void setCurrentSource( const QUrl& stream ); void setCurrentSource( const QUrl& stream, bool preload );
void setCurrentSource( QIODevice* stream ); void setCurrentSource( QIODevice* stream, bool preload );
void setCurrentSource( MediaStream* stream ); void setCurrentSource( MediaStream* stream, bool preload );
void setPreloadedSourceAsCurrent( void );
void play(); void play();
void pause(); void pause();
@@ -65,13 +66,15 @@ public:
qreal volume() const; qreal volume() const;
qint64 currentTime() const; qint64 currentTime() const;
qint64 totalTime() const; qint64 totalTime() const;
void setAutoDelete ( bool ad ); void setAutoDelete ( bool ad, bool preload );
void setDspCallback( std::function< void( int, int, float*, int, int ) > cb ); void setDspCallback( std::function< void( int, int, float*, int, int ) > cb );
static AudioOutput* instance(); static AudioOutput* instance();
libvlc_instance_t* vlcInstance() const; libvlc_instance_t* vlcInstance() const;
void switchToPreloadedMedia( void );
public slots: public slots:
signals: signals:
@@ -90,6 +93,7 @@ private:
void setCurrentPosition( float position ); void setCurrentPosition( float position );
void setTotalTime( qint64 time ); void setTotalTime( qint64 time );
void onVlcEvent( const libvlc_event_t* event ); void onVlcEvent( const libvlc_event_t* event );
static void vlcEventCallback( const libvlc_event_t* event, void* opaque ); static void vlcEventCallback( const libvlc_event_t* event, void* opaque );
static void s_dspCallback( int frameNumber, float* samples, int nb_channels, int nb_samples ); static void s_dspCallback( int frameNumber, float* samples, int nb_channels, int nb_samples );
@@ -97,9 +101,11 @@ private:
static AudioOutput* s_instance; static AudioOutput* s_instance;
AudioState m_currentState; AudioState m_currentState;
MediaStream* m_currentStream; MediaStream* m_currentStream;
MediaStream* m_preloadedStream;
bool m_seekable; bool m_seekable;
bool m_muted; bool m_muted;
bool m_autoDelete; bool m_autoDelete;
bool m_preloadedAutoDelete;
bool m_havePosition; bool m_havePosition;
bool m_haveTiming; bool m_haveTiming;
qreal m_volume; qreal m_volume;
@@ -107,7 +113,7 @@ private:
qint64 m_totalTime; qint64 m_totalTime;
bool m_justSeeked; bool m_justSeeked;
bool m_initialized; int m_initialized;
QFile m_silenceFile; QFile m_silenceFile;
std::function< void( int state, int frameNumber, float* samples, int nb_channels, int nb_samples ) > dspPluginCallback; std::function< void( int state, int frameNumber, float* samples, int nb_channels, int nb_samples ) > dspPluginCallback;
@@ -115,6 +121,9 @@ private:
libvlc_instance_t* m_vlcInstance; libvlc_instance_t* m_vlcInstance;
libvlc_media_player_t* m_vlcPlayer; libvlc_media_player_t* m_vlcPlayer;
libvlc_media_t* m_vlcMedia; libvlc_media_t* m_vlcMedia;
libvlc_media_player_t* m_vlcBackPlayer;
libvlc_media_player_t* m_vlcPreloadedPlayer;
libvlc_media_t* m_vlcPreloadedMedia;
}; };
#endif // AUDIOOUTPUT_H #endif // AUDIOOUTPUT_H

View File

@@ -190,7 +190,7 @@ JSAccount::reportNativeScriptJobResult( int resultId, const QVariantMap& result
.arg( serializeQVariantMap( result ) ); .arg( serializeQVariantMap( result ) );
// Remove when new scripting api turned out to work reliably // Remove when new scripting api turned out to work reliably
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << eval; //tDebug( LOGVERBOSE ) << Q_FUNC_INFO << eval;
evaluateJavaScript( eval ); evaluateJavaScript( eval );
} }