mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-07 14:46:33 +02:00
Precache next track to play when reaching end of current song
This commit is contained in:
@@ -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);
|
||||||
|
@@ -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,6 +589,18 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (preload && d->preloadedTrack == result)
|
||||||
|
return;
|
||||||
|
|
||||||
|
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
|
// 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
|
// If we don't block the audioOutput signals, the state change will trigger
|
||||||
// loading yet another track
|
// loading yet another track
|
||||||
@@ -597,10 +609,37 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
|
|||||||
d->audioOutput->blockSignals( false );
|
d->audioOutput->blockSignals( false );
|
||||||
|
|
||||||
setCurrentTrack( result );
|
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;
|
||||||
@@ -726,10 +776,17 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString&
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( !err )
|
if ( !err )
|
||||||
|
{
|
||||||
|
if (preload)
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Preloading new song:" << url;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
tLog() << Q_FUNC_INFO << "Starting new song:" << url;
|
tLog() << Q_FUNC_INFO << "Starting new song:" << url;
|
||||||
d->state = Loading;
|
d->state = Loading;
|
||||||
emit loading( d->currentTrack );
|
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,12 +834,22 @@ 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 ( preload ) {
|
||||||
|
if ( !d->inputPreloaded.isNull() )
|
||||||
|
{
|
||||||
|
d->inputPreloaded->close();
|
||||||
|
d->inputPreloaded.clear();
|
||||||
|
}
|
||||||
|
d->inputPreloaded = ioToKeep;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if ( !d->input.isNull() )
|
if ( !d->input.isNull() )
|
||||||
{
|
{
|
||||||
d->input->close();
|
d->input->close();
|
||||||
@@ -799,6 +866,7 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString&
|
|||||||
sendNowPlayingNotification( Tomahawk::InfoSystem::InfoNowPlaying );
|
sendNowPlayingNotification( Tomahawk::InfoSystem::InfoNowPlaying );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( err )
|
if ( err )
|
||||||
{
|
{
|
||||||
@@ -806,7 +874,10 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString&
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( !preload )
|
||||||
|
{
|
||||||
d->waitingOnNewTrack = false;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -862,9 +934,12 @@ AudioEngine::loadNextTrack()
|
|||||||
if ( d->stopAfterTrack && d->currentTrack )
|
if ( d->stopAfterTrack && d->currentTrack )
|
||||||
{
|
{
|
||||||
if ( d->stopAfterTrack->track()->equals( d->currentTrack->track() ) )
|
if ( d->stopAfterTrack->track()->equals( d->currentTrack->track() ) )
|
||||||
|
{
|
||||||
|
if ( !preload )
|
||||||
{
|
{
|
||||||
d->stopAfterTrack.clear();
|
d->stopAfterTrack.clear();
|
||||||
stop();
|
stop();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -881,18 +956,25 @@ AudioEngine::loadNextTrack()
|
|||||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Loading playlist's next item" << d->playlist.data() << d->playlist->shuffled();
|
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Loading playlist's next item" << d->playlist.data() << d->playlist->shuffled();
|
||||||
|
|
||||||
if ( d->playlist.data()->nextResult() )
|
if ( d->playlist.data()->nextResult() )
|
||||||
|
{
|
||||||
|
if ( preload )
|
||||||
|
{
|
||||||
|
result = d->playlist.data()->nextResult();
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
result = d->playlist.data()->setSiblingResult( 1 );
|
result = d->playlist.data()->setSiblingResult( 1 );
|
||||||
setCurrentTrackPlaylist( d->playlist );
|
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 )
|
||||||
{
|
{
|
||||||
|
@@ -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();
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
@@ -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,8 +127,15 @@ 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[] = {
|
|
||||||
|
for( auto player : { m_vlcPlayer, m_vlcPreloadedPlayer } )
|
||||||
|
{
|
||||||
|
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_MediaPlayerMediaChanged,
|
||||||
libvlc_MediaPlayerNothingSpecial,
|
libvlc_MediaPlayerNothingSpecial,
|
||||||
libvlc_MediaPlayerOpening,
|
libvlc_MediaPlayerOpening,
|
||||||
@@ -153,7 +164,9 @@ AudioOutput::AudioOutput( QObject* parent )
|
|||||||
const int eventCount = sizeof(events) / sizeof( *events );
|
const int eventCount = sizeof(events) / sizeof( *events );
|
||||||
for ( int i = 0; i < eventCount; i++ )
|
for ( int i = 0; i < eventCount; i++ )
|
||||||
{
|
{
|
||||||
libvlc_event_attach( manager, events[ i ], &AudioOutput::vlcEventCallback, this );
|
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";
|
||||||
|
if (m_initialized >=2)
|
||||||
|
{
|
||||||
|
m_silenceFile.close();
|
||||||
emit initialized();
|
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 )
|
||||||
{
|
{
|
||||||
|
if (preload)
|
||||||
|
m_preloadedAutoDelete = ad;
|
||||||
|
else
|
||||||
m_autoDelete = ad;
|
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;
|
||||||
|
|
||||||
|
if ( !preload )
|
||||||
setState( Loading );
|
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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -575,6 +645,8 @@ AudioOutput::setVolume( qreal vol )
|
|||||||
|
|
||||||
void
|
void
|
||||||
AudioOutput::onVlcEvent( const libvlc_event_t* event )
|
AudioOutput::onVlcEvent( const libvlc_event_t* event )
|
||||||
|
{
|
||||||
|
if ( event->p_obj == m_vlcPlayer || event->p_obj == m_vlcMedia )
|
||||||
{
|
{
|
||||||
switch ( event->type )
|
switch ( event->type )
|
||||||
{
|
{
|
||||||
@@ -610,6 +682,7 @@ AudioOutput::onVlcEvent( const libvlc_event_t* event )
|
|||||||
#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;
|
||||||
|
tDebug() << Q_FUNC_INFO << "Got signal in current player that volume changed to:" << m_volume;
|
||||||
emit volumeChanged( volume() );
|
emit volumeChanged( volume() );
|
||||||
break;
|
break;
|
||||||
case libvlc_MediaPlayerMuted:
|
case libvlc_MediaPlayerMuted:
|
||||||
@@ -636,6 +709,46 @@ AudioOutput::onVlcEvent( const libvlc_event_t* event )
|
|||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@@ -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
|
||||||
|
@@ -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 );
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user