예제 #1
0
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();
    }
}
예제 #2
0
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 );
    }
}
예제 #3
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> ) ) );
}
예제 #4
0
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;
}
예제 #5
0
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;
}
예제 #6
0
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();
}
예제 #7
0
ACLJobDelegate::~ACLJobDelegate()
{
    tLog() << Q_FUNC_INFO;
}
예제 #8
0
ACLJobDelegate::ACLJobDelegate( QObject* parent )
    : QStyledItemDelegate ( parent )
{
    tLog() << Q_FUNC_INFO;
}
예제 #9
0
void
QtScriptResolverHelper::log( const QString& message )
{
    tLog() << m_scriptPath << ":" << message;
}
예제 #10
0
void
ScriptEngine::javaScriptConsoleMessage( const QString& message, int lineNumber, const QString& sourceID )
{
    tLog() << "JAVASCRIPT:" << m_scriptPath << message << lineNumber << sourceID;
    Q_ASSERT( false );
}
예제 #11
0
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();
}
예제 #12
0
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;
        }
    }
}
예제 #13
0
void cParamServer::InitLog()
{
	mLog = tLog();
}
예제 #14
0
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 );
}
예제 #15
0
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 );
}
예제 #16
0
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();
}
예제 #17
0
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() ) );
}
예제 #18
0
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 );
}