void DownloadJob::onDownloadError( QNetworkReply::NetworkError code ) { if ( code == QNetworkReply::NoError ) return; if ( m_state == Aborted ) return; tLog() << "Download error for track:" << toString() << "-" << code; if ( ++m_retries > 3 ) { setState( Failed ); } else { m_tryResuming = true; download(); } }
DatabaseImpl::DatabaseImpl( const QString& dbname ) { QTime t; t.start(); bool schemaUpdated = openDatabase( dbname ); tDebug( LOGVERBOSE ) << "Opened database:" << t.elapsed(); TomahawkSqlQuery query = newquery(); query.exec( "SELECT v FROM settings WHERE k='dbid'" ); if ( query.next() ) { m_dbid = query.value( 0 ).toString(); } else { m_dbid = uuid(); query.exec( QString( "INSERT INTO settings(k,v) VALUES('dbid','%1')" ).arg( m_dbid ) ); } tLog() << "Database ID:" << m_dbid; init(); query.exec( "PRAGMA auto_vacuum = FULL" ); query.exec( "PRAGMA synchronous = NORMAL" ); tDebug( LOGVERBOSE ) << "Tweaked db pragmas:" << t.elapsed(); // in case of unclean shutdown last time: query.exec( "UPDATE source SET isonline = 'false'" ); query.exec( "DELETE FROM oplog WHERE source IS NULL AND singleton = 'true'" ); m_fuzzyIndex = new FuzzyIndex( this, schemaUpdated ); tDebug( LOGVERBOSE ) << "Loaded index:" << t.elapsed(); if ( qApp->arguments().contains( "--dumpdb" ) ) { dumpDatabase(); ::exit( 0 ); } }
ScriptEngine::ScriptEngine( JSResolver* parent ) : QWebPage( (QObject*) parent ) , m_parent( parent ) { settings()->setAttribute( QWebSettings::OfflineStorageDatabaseEnabled, true ); settings()->setOfflineStoragePath( TomahawkUtils::appDataDir().path() ); settings()->setAttribute(QWebSettings::LocalStorageEnabled, true ); settings()->setLocalStoragePath( TomahawkUtils::appDataDir().path() ); settings()->setAttribute( QWebSettings::LocalStorageDatabaseEnabled, true ); settings()->setAttribute( QWebSettings::LocalContentCanAccessFileUrls, true ); settings()->setAttribute( QWebSettings::LocalContentCanAccessRemoteUrls, true ); // Tomahawk is not a user agent m_header = QWebPage::userAgentForUrl( QUrl() ).replace( QString( "%1/%2" ) .arg( TOMAHAWK_APPLICATION_NAME ) .arg( TOMAHAWK_VERSION ) , "" ); tLog( LOGVERBOSE ) << "JSResolver Using header" << m_header; connect( networkAccessManager(), SIGNAL( sslErrors( QNetworkReply*, QList<QSslError> ) ), SLOT( sslErrorHandler( QNetworkReply*, QList<QSslError> ) ) ); }
QString SipStatusMessage::mainText() const { Q_D( const SipStatusMessage ); QString text; switch( d->statusMessageType ) { case SipInviteFailure: text = "Could not invite %1. Please check his/her id!"; break; case SipInviteSuccess: text = "Invitation sent to %1!"; break; case SipAuthReceived: text = "Received authorization from %1"; break; case SipLoginFailure: text = "Could not login to %1. Please check your user credentials!"; break; case SipConnectionFailure: text = "Could not connect to %1: %2"; break; default: tLog() << Q_FUNC_INFO << "Not all status types handled"; Q_ASSERT(false); } text = text.arg( d->contactId ); if(text.contains( "%2") ) text = text.arg( d->message ); return text; }
tCLinkage tExport bool tPointsExpander( const char *src_abc_path, const char *dst_abc_path, const PointsExpanderConfig *conf) { if (!src_abc_path || !dst_abc_path || !conf) { tLog("tPointsExpander(): parameter is null\n"); return false; } aiConfig iconf; aeConfig econf; aiContext *ictx = aiCreateContext(0); aiSetConfig(ictx, &iconf); if (!aiLoad(ictx, src_abc_path)) { return false; } aeContext *ectx = aeCreateContext(); if (!aeOpenArchive(ectx, dst_abc_path)) { aiDestroyContext(ictx); return false; } { tContext tctx; tctx.setExportConfig(econf); tctx.setArchives(ictx, ectx); tPointsExpanderConvert(&tctx, conf); } aeDestroyContext(ectx); aiDestroyContext(ictx); return false; }
void HatchetSipPlugin::connectWebSocket() { tLog() << Q_FUNC_INFO; if ( m_webSocketThreadController ) { tLog() << Q_FUNC_INFO << "Already have a thread running, bailing"; return; } m_webSocketThreadController = QPointer< WebSocketThreadController >( new WebSocketThreadController( this ) ); if ( !m_webSocketThreadController ) { tLog() << Q_FUNC_INFO << "Could not create a new thread, bailing"; disconnectPlugin(); return; } if ( !isValid() ) { tLog() << Q_FUNC_INFO << "Invalid state, not continuing with connection"; return; } m_token = m_account->credentials()[ "dreamcatcher_access_token" ].toString(); if ( m_token.isEmpty() ) { tLog() << Q_FUNC_INFO << "Unable to find an access token"; disconnectPlugin(); return; } QString url( "wss://dreamcatcher.hatchet.is:443" ); tLog() << Q_FUNC_INFO << "Connecting to Dreamcatcher endpoint at: " << url; m_webSocketThreadController->setUrl( url ); m_webSocketThreadController->start(); }
ACLJobDelegate::~ACLJobDelegate() { tLog() << Q_FUNC_INFO; }
ACLJobDelegate::ACLJobDelegate( QObject* parent ) : QStyledItemDelegate ( parent ) { tLog() << Q_FUNC_INFO; }
void QtScriptResolverHelper::log( const QString& message ) { tLog() << m_scriptPath << ":" << message; }
void ScriptEngine::javaScriptConsoleMessage( const QString& message, int lineNumber, const QString& sourceID ) { tLog() << "JAVASCRIPT:" << m_scriptPath << message << lineNumber << sourceID; Q_ASSERT( false ); }
void Connection::doSetup() { Q_D( Connection ); tDebug( LOGVERBOSE ) << Q_FUNC_INFO << thread() << d->id; /* New connections can be created from other thread contexts, such as when AudioEngine calls getIODevice.. - we need to ensure that connections and their associated sockets are running in the same thread as the servent. HINT: export QT_FATAL_WARNINGS=1 helps to catch these kind of errors. */ if ( QThread::currentThread() != d->servent->thread() ) { // Connections should always be in the same thread as the servent. moveToThread( d->servent->thread() ); } if ( !d->setup ) { // We only want to setup this connection once d->setup = true; //stats timer calculates BW used by this connection d->statstimer = new QTimer; d->statstimer->moveToThread( this->thread() ); d->statstimer->setInterval( 1000 ); connect( d->statstimer, SIGNAL( timeout() ), SLOT( calcStats() ) ); d->statstimer->start(); d->statstimer_mark.start(); d->sock->moveToThread( thread() ); connect( d->sock.data(), SIGNAL( bytesWritten( qint64 ) ), SLOT( bytesWritten( qint64 ) ), Qt::QueuedConnection ); connect( d->sock.data(), SIGNAL( disconnected() ), SLOT( socketDisconnected() ), Qt::QueuedConnection ); connect( d->sock.data(), SIGNAL( error( QAbstractSocket::SocketError ) ), SLOT( socketDisconnectedError( QAbstractSocket::SocketError ) ), Qt::QueuedConnection ); connect( d->sock.data(), SIGNAL( readyRead() ), SLOT( readyRead() ), Qt::QueuedConnection ); // if connection not authed/setup fast enough, kill it: QTimer::singleShot( AUTH_TIMEOUT, this, SLOT( authCheckTimeout() ) ); if ( outbound() ) { Q_ASSERT( !d->firstmsg.isNull() ); sendMsg( d->firstmsg ); } else { sendMsg( Msg::factory( PROTOVER, Msg::SETUP ) ); } } else { tLog() << Q_FUNC_INFO << QThread::currentThread() << d->id << "Duplicate doSetup call"; } // call readyRead incase we missed the signal in between the servent disconnecting and us // connecting to the signal - won't do anything if there are no bytesAvailable anyway. readyRead(); }
void DownloadJob::onDownloadProgress( qint64 rcvd, qint64 total ) { if ( m_reply == 0 ) return; if ( rcvd >= m_fileSize && m_fileSize > 0 ) { m_finished = true; } if ( state() == Paused ) return; m_rcvdSize = rcvd; m_fileSize = total; qint64 now = QDateTime::currentDateTime().toMSecsSinceEpoch(); if ( ( now - 50 > m_rcvdStamp ) || ( rcvd == total ) ) { m_rcvdStamp = now; if ( ( m_rcvdSize - 16384 > m_rcvdEmit ) || ( rcvd == total ) ) { m_rcvdEmit = m_rcvdSize; emit progress( progressPercentage() ); } } if ( !m_file ) return; if ( !m_file->isOpen() ) { if ( m_tryResuming && checkForResumedFile() ) return; if ( !m_file->open( QIODevice::WriteOnly ) ) { tLog() << Q_FUNC_INFO << "Failed opening file:" << m_file->fileName(); setState( Failed ); return; } } QByteArray data = m_reply->readAll(); if ( data.isEmpty() ) return; if ( m_file->write( data ) < 0 ) { tLog() << Q_FUNC_INFO << "Failed writing to file:" << data.length(); onDownloadError( QNetworkReply::UnknownContentError ); return; } if ( m_rcvdSize >= m_fileSize && m_fileSize > 0 ) { onDownloadFinished(); } else if ( m_reply->isFinished() && m_reply->bytesAvailable() == 0 ) { if ( ( m_fileSize > 0 && m_rcvdSize < m_fileSize ) || m_rcvdSize == 0 ) { onDownloadError( QNetworkReply::UnknownContentError ); return; } } }
void cParamServer::InitLog() { mLog = tLog(); }
DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) : QObject( (QObject*) parent ) , m_lastartid( 0 ) , m_lastalbid( 0 ) , m_lasttrkid( 0 ) { bool schemaUpdated = false; int version = getDatabaseVersion( dbname ); if ( version > 0 && version != CURRENT_SCHEMA_VERSION ) { QString newname = QString( "%1.v%2" ).arg( dbname ).arg( version ); tLog() << endl << "****************************" << endl; tLog() << "Schema version too old: " << version << ". Current version is:" << CURRENT_SCHEMA_VERSION; tLog() << "Moving" << dbname << newname; tLog() << "If the migration fails, you can recover your DB by copying" << newname << "back to" << dbname; tLog() << endl << "****************************" << endl; QFile::copy( dbname, newname ); { db = QSqlDatabase::addDatabase( "QSQLITE", "tomahawk" ); db.setDatabaseName( dbname ); if( !db.open() ) throw "db moving failed"; TomahawkSqlQuery query = newquery(); query.exec( "PRAGMA auto_vacuum = FULL" ); schemaUpdated = updateSchema( version ); if ( !schemaUpdated ) { Q_ASSERT( false ); QTimer::singleShot( 0, qApp, SLOT( quit() ) ); } } } else { db = QSqlDatabase::addDatabase( "QSQLITE", "tomahawk" ); db.setDatabaseName( dbname ); if ( !db.open() ) { tLog() << "Failed to open database" << dbname; throw "failed to open db"; // TODO } if ( version < 0 ) schemaUpdated = updateSchema( 0 ); } TomahawkSqlQuery query = newquery(); query.exec( "SELECT v FROM settings WHERE k='dbid'" ); if( query.next() ) { m_dbid = query.value( 0 ).toString(); } else { m_dbid = uuid(); query.exec( QString( "INSERT INTO settings(k,v) VALUES('dbid','%1')" ).arg( m_dbid ) ); } tLog() << "Database ID:" << m_dbid; // make sqlite behave how we want: query.exec( "PRAGMA synchronous = ON" ); query.exec( "PRAGMA foreign_keys = ON" ); //query.exec( "PRAGMA temp_store = MEMORY" ); // in case of unclean shutdown last time: query.exec( "UPDATE source SET isonline = 'false'" ); m_fuzzyIndex = new FuzzyIndex( *this, schemaUpdated ); }
void TwitterInfoPlugin::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) { tDebug() << Q_FUNC_INFO; if ( !isValid() ) { tDebug() << Q_FUNC_INFO << "Plugin not valid, deleting and returning"; deleteLater(); return; } Tomahawk::InfoSystem::PushInfoPair pushInfoPair = pushData.infoPair; if ( !pushInfoPair.second.canConvert< QVariantMap >() ) { tLog() << Q_FUNC_INFO << "Failed to find QVariantMap!"; return; } QVariantMap map = pushInfoPair.second.toMap(); if ( !map.contains( "accountlist" ) || !map[ "accountlist" ].canConvert< QStringList >() ) { tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Cowardly failing to send out a message without an account list present"; return; } const QStringList accountList = map[ "accountlist" ].toStringList(); if ( !accountList.contains( "all" ) && !accountList.contains( m_account->accountId() ) ) { tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Our account not in the list, not tweeting out"; return; } if ( !map.contains( "message" ) && ( !map.contains( "trackinfo" ) || !map[ "trackinfo" ].canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) ) { tLog() << Q_FUNC_INFO << "Failed to find message or trackinfo"; return; } Tomahawk::InfoSystem::InfoStringHash info; QString msg; if ( !map.contains( "message" ) ) { info = map[ "trackinfo" ].value< Tomahawk::InfoSystem::InfoStringHash >(); msg = tr( "Listening to \"%1\" by %2 and loving it! %3" ) .arg( info[ "title" ] ) .arg( info[ "artist" ] ) .arg( pushInfoPair.first.contains( "shorturl" ) ? pushInfoPair.first[ "shorturl" ].toUrl().toString() : GlobalActionManager::instance()->openLink( info[ "title" ], info[ "artist" ], info[ "album" ] ).toString() ); } else msg = map[ "message" ].toString(); QTweetStatusUpdate *statUpdate = new QTweetStatusUpdate( m_twitterAuth.data(), this ); connect( statUpdate, SIGNAL( postedStatus(const QTweetStatus &) ), SLOT( postLovedStatusUpdateReply(const QTweetStatus &) ) ); connect( statUpdate, SIGNAL( error(QTweetNetBase::ErrorCode, const QString&) ), SLOT( postLovedStatusUpdateError(QTweetNetBase::ErrorCode, const QString &) ) ); tDebug() << Q_FUNC_INFO << "Posting message:" << msg; statUpdate->post( msg ); }
tCLinkage tExport void tPointsExpanderConvert(tContext *tctx_, const PointsExpanderConfig *conf) { tContext& tctx = *tctx_; tLogSetCallback(conf->logCB); tctx.setPointsProcessor([&](aiPoints *iobj, aePoints *eobj) { double time_proc_begin = tGetTime(); const char* target_name = aiGetNameS(aiGetParent(aiSchemaGetObject(iobj))); tLog("processing \"%s\"\n", target_name); tPointsBuffer buf; std::vector<uint64_t> ids, ids_tmp1, ids_tmp2; std::vector<char> point_info; aiPointsSummary summary; aiPointsGetSummary(iobj, &summary); int num_samples = aiSchemaGetNumSamples(iobj); // build list of all ids for (int i = 0; i < num_samples; ++i) { auto ss = aiIndexToSampleSelector(i); aiSchemaUpdateSample(iobj, &ss); auto *sample = aiSchemaGetSample(iobj, &ss); aiPointsData idata; aiPointsGetDataPointer(sample, &idata); ids_tmp1.assign(idata.ids, idata.ids + idata.count); ist::parallel_sort(ids_tmp1.begin(), ids_tmp1.end()); ids_tmp2.resize(ids_tmp1.size() + ids.size()); std::merge(ids_tmp1.begin(), ids_tmp1.end(), ids.begin(), ids.end(), ids_tmp2.begin()); ids_tmp2.erase(std::unique(ids_tmp2.begin(), ids_tmp2.end()), ids_tmp2.end()); ids.assign(ids_tmp2.begin(), ids_tmp2.end()); } tLog(" listed all IDs. %d elements (%.2lfms)\n", (int)ids.size(), tGetTime() - time_proc_begin); // size_t info_size = size_t(sizeof(tPointInfoHeader) + sizeof(tPointInfo) * std::ceil(conf->count_rate)); uint64_t id_range = summary.maxID - summary.minID + 1; point_info.resize(info_size * (size_t)id_range); auto getPointInfoByID = [&](uint64_t id) -> tPointInfoHeader& { return (tPointInfoHeader&)point_info[info_size * size_t(id - summary.minID)]; }; tRandSetSeed(conf->random_seed); uint64_t id_size_scaled = uint64_t((double)ids.size() * conf->count_rate); for (size_t pi = 0; pi < id_size_scaled; ++pi) { size_t spi = size_t((double)pi / conf->count_rate); uint64_t id = ids[spi]; tPointInfo &pf = getPointInfoByID(id).push(); pf.id = (uint32_t)pi; pf.random_diffuse = conf->random_diffuse * tRand3(); } mpKernelParams mpparams; mpparams.damping = conf->repulse_damping; mpparams.advection = conf->repulse_advection; mpparams.max_particles = int(summary.peakCount * std::ceil(conf->count_rate)); mpparams.particle_size = conf->repulse_particle_size; mpparams.pressure_stiffness = conf->repulse_stiffness; auto mp = mpCreateContext(); // process all frames for (int fi = 0; fi < num_samples; ++fi) { double time_frame_begin = tGetTime(); auto ss = aiIndexToSampleSelector(fi); // get points data from alembic aiSchemaUpdateSample(iobj, &ss); auto *sample = aiSchemaGetSample(iobj, &ss); aiPointsData idata; aiPointsGetDataPointer(sample, &idata); // create inc/decreased points buffer size_t num_scaled = 0; for (int pi = 0; pi < idata.count; ++pi) { tPointInfoHeader& pinfo = getPointInfoByID(idata.ids[pi]); num_scaled += pinfo.num; } buf.allocate(num_scaled, idata.velocities != nullptr); for (int pi = 0, spi = 0; pi < idata.count; ++pi) { getPointInfoByID(idata.ids[pi]).each([&](const tPointInfo &pinfo) { buf.positions[spi] = (float3&)idata.positions[pi] + pinfo.random_diffuse; buf.ids[spi] = pinfo.id; if (idata.velocities) { buf.velocities[spi] = (float3&)idata.velocities[pi]; } ++spi; }); } // repulsion if (conf->repulse_iteration > 0) { mpparams.world_center = (mpV3&)idata.center; mpparams.world_extent = (mpV3&)idata.size; mpparams.world_div = mpV3i( std::min<int>(int(mpparams.world_extent.x * 2.0f / conf->repulse_particle_size), 256), std::min<int>(int(mpparams.world_extent.y * 2.0f / conf->repulse_particle_size), 256), std::min<int>(int(mpparams.world_extent.z * 2.0f / conf->repulse_particle_size), 256) ); // apply repulsion mpSetKernelParams(mp, &mpparams); mpClearParticles(mp); mpForceSetNumParticles(mp, (int)num_scaled); mpParticle *particles = mpGetParticles(mp); for (size_t pi = 0; pi < num_scaled; ++pi) { particles[pi].position = (mpV3&)buf.positions[pi]; particles[pi].velocity = mpV3(); particles[pi].lifetime = std::numeric_limits<float>::max(); particles[pi].userdata = (int)pi; } for (int ri = 0; ri < conf->repulse_iteration; ++ri) { mpUpdate(mp, conf->repulse_timestep); } ist::parallel_sort(particles, particles + num_scaled, [](const mpParticle& a, const mpParticle& b) { return a.userdata < b.userdata; }); for (size_t pi = 0; pi < num_scaled; ++pi) { buf.positions[pi] = (float3&)particles[pi].position; } if (idata.velocities) { for (size_t pi = 0; pi < num_scaled; ++pi) { buf.velocities[pi] = (float3&)particles[pi].velocity; } } } auto edata = buf.asExportData(); aePointsWriteSample(eobj, &edata); tLog(" frame %d: %d -> %d points (%.2lfms)\n", fi, idata.count, (int)num_scaled, tGetTime() - time_frame_begin); } mpDestroyContext(mp); tLog("finished \"%s\" (%.2lfms)\n", target_name, tGetTime() - time_proc_begin); }); tctx.doExport(); }
void DatabaseWorker::doWork() { /* Run the dbcmd. Only inside a transaction if the cmd does mutates. If the cmd is modifying local content (ie source->isLocal()) then log to the database oplog for replication to peers. */ #ifdef DEBUG_TIMING QTime timer; timer.start(); #endif QList< QSharedPointer<DatabaseCommand> > cmdGroup; QSharedPointer<DatabaseCommand> cmd; { QMutexLocker lock( &m_mut ); cmd = m_commands.takeFirst(); } if ( cmd->doesMutates() ) { bool transok = m_dbimpl->database().transaction(); Q_ASSERT( transok ); Q_UNUSED( transok ); } unsigned int completed = 0; try { bool finished = false; { while ( !finished ) { completed++; cmd->_exec( m_dbimpl ); // runs actual SQL stuff if ( cmd->loggable() ) { // We only save our own ops to the oplog, since incoming ops from peers // are applied immediately. // // Crazy idea: if peers had keypairs and could sign ops/msgs, in theory it // would be safe to sync ops for friend A from friend B's cache, if he saved them, // which would mean you could get updates even if a peer was offline. if ( cmd->source()->isLocal() && !cmd->localOnly() ) { // save to op-log DatabaseCommandLoggable* command = (DatabaseCommandLoggable*)cmd.data(); logOp( command ); } else { // Make a note of the last guid we applied for this source // so we can always request just the newer ops in future. // if ( !cmd->singletonCmd() ) { TomahawkSqlQuery query = m_dbimpl->newquery(); query.prepare( "UPDATE source SET lastop = ? WHERE id = ?" ); query.addBindValue( cmd->guid() ); query.addBindValue( cmd->source()->id() ); if ( !query.exec() ) { throw "Failed to set lastop"; } } } } cmdGroup << cmd; if ( cmd->groupable() && !m_commands.isEmpty() ) { QMutexLocker lock( &m_mut ); if ( m_commands.first()->groupable() ) { cmd = m_commands.takeFirst(); } else { finished = true; } } else finished = true; } if ( cmd->doesMutates() ) { qDebug() << "Committing" << cmd->commandname() << cmd->guid(); if ( !m_dbimpl->database().commit() ) { tDebug() << "FAILED TO COMMIT TRANSACTION*"; throw "commit failed"; } } #ifdef DEBUG_TIMING uint duration = timer.elapsed(); tDebug() << "DBCmd Duration:" << duration << "ms, now running postcommit for" << cmd->commandname(); #endif foreach ( QSharedPointer<DatabaseCommand> c, cmdGroup ) c->postCommit(); #ifdef DEBUG_TIMING tDebug() << "Post commit finished in" << timer.elapsed() - duration << "ms for" << cmd->commandname(); #endif } } catch( const char * msg ) { tLog() << endl << "*ERROR* processing databasecommand:" << cmd->commandname() << msg << m_dbimpl->database().lastError().databaseText() << m_dbimpl->database().lastError().driverText() << endl; if ( cmd->doesMutates() ) m_dbimpl->database().rollback(); Q_ASSERT( false ); } catch(...) { qDebug() << "Uncaught exception processing dbcmd"; if ( cmd->doesMutates() ) m_dbimpl->database().rollback(); Q_ASSERT( false ); throw; } foreach ( QSharedPointer<DatabaseCommand> c, cmdGroup ) c->emitFinished(); QMutexLocker lock( &m_mut ); m_outstanding -= completed; if ( m_outstanding > 0 ) QTimer::singleShot( 0, this, SLOT( doWork() ) ); }
void AudioOutput::setCurrentSource( MediaStream* stream ) { tDebug() << Q_FUNC_INFO; setState( Loading ); if ( m_vlcMedia != nullptr ) { // Ensure playback is stopped, then release media libvlc_media_player_stop( m_vlcPlayer ); libvlc_media_release( m_vlcMedia ); m_vlcMedia = nullptr; } if ( m_autoDelete && m_currentStream != nullptr ) { delete m_currentStream; } m_currentStream = stream; m_totalTime = 0; m_currentTime = 0; m_justSeeked = false; m_seekable = true; QByteArray url; switch ( stream->type() ) { case MediaStream::Unknown: tDebug() << Q_FUNC_INFO << "MediaStream Type is Invalid:" << stream->type(); break; case MediaStream::Empty: tDebug() << Q_FUNC_INFO << "MediaStream is empty."; break; case MediaStream::Url: tDebug() << Q_FUNC_INFO << "MediaStream::Url:" << stream->url(); if ( stream->url().scheme().isEmpty() ) { url = "file:///"; if ( stream->url().isRelative() ) { url.append( QFile::encodeName( QDir::currentPath() ) + '/' ); } } url += stream->url().toEncoded(); break; case MediaStream::Stream: case MediaStream::IODevice: url = QByteArray( "imem://" ); break; } tDebug() << Q_FUNC_INFO << "MediaStream::Final Url:" << url; m_vlcMedia = libvlc_media_new_location( m_vlcInstance, url.constData() ); libvlc_event_manager_t* manager = libvlc_media_event_manager( m_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( m_vlcPlayer, m_vlcMedia ); if ( stream->type() == MediaStream::Url ) { m_totalTime = libvlc_media_get_duration( m_vlcMedia ); } else if ( stream->type() == MediaStream::Stream || stream->type() == MediaStream::IODevice ) { libvlc_media_add_option_flag(m_vlcMedia, "imem-cat=4", libvlc_media_option_trusted); const char* imemData = QString( "imem-data=%1" ).arg( (uintptr_t)stream ).toLatin1().constData(); libvlc_media_add_option_flag(m_vlcMedia, imemData, libvlc_media_option_trusted); const char* imemGet = QString( "imem-get=%1" ).arg( (uintptr_t)&readCallback ).toLatin1().constData(); libvlc_media_add_option_flag(m_vlcMedia, imemGet, libvlc_media_option_trusted); const char* imemRelease = QString( "imem-release=%1" ).arg( (uintptr_t)&readDoneCallback ).toLatin1().constData(); libvlc_media_add_option_flag(m_vlcMedia, imemRelease, libvlc_media_option_trusted); const char* imemSeek = QString( "imem-seek=%1" ).arg( (uintptr_t)&MediaStream::seekCallback ).toLatin1().constData(); libvlc_media_add_option_flag(m_vlcMedia, imemSeek, libvlc_media_option_trusted); } if ( qApp->arguments().contains( "--chromecast-ip" ) ) { // This is very basic chromecast support through VLC 3+. // Totally unstable, unusable and will suck more CPU than you can think of. // If you want to improve this, please talk to the guys in #videolan and // support them. // // Knonw problems: // 1. It does not work eventhough the IP is correct. // -> Open vlc with the same commandline and accept the Certificate in the VLC UI. if ( qApp->arguments().length() > 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}" ); libvlc_media_add_option( m_vlcMedia, sout.arg( castIP ).toLatin1().constData() ); } else { tLog() << Q_FUNC_INFO << "Chromecast option but no IP supplied."; } } // setState( Stopped ); }