Пример #1
0
InteractiveTV::InteractiveTV(MythPlayer *nvp)
    : m_context(new MHIContext(this)), m_nvp(nvp)
{
    Restart(0, 0, false);

    MHSetLogging(stdout,
        VERBOSE_LEVEL_CHECK(VB_MHEG, LOG_DEBUG) ? MHLogAll :
        VERBOSE_LEVEL_CHECK(VB_MHEG, LOG_ANY) ?
            MHLogError | MHLogWarning | MHLogNotifications /*| MHLogLinks | MHLogActions | MHLogDetail*/ :
        MHLogError | MHLogWarning );
}
Пример #2
0
/** \fn LiveTVChain::SwitchTo(int)
 *  \brief Sets the recording to switch to.
 *  \param num Index of recording to switch to, -1 for last recording.
 */
void LiveTVChain::SwitchTo(int num)
{
    QMutexLocker lock(&m_lock);

    LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("SwitchTo(%1)").arg(num));

    int size = m_chain.count();
    if ((num < 0) || (num >= size))
        num = size - 1;

    if (m_curpos != num)
    {
        m_switchid = num;
        GetEntryAt(num, m_switchentry);
    }
    else
        LOG(VB_GENERAL, LOG_ERR, LOC + "SwitchTo() not switching to current");

    if (VERBOSE_LEVEL_CHECK(VB_PLAYBACK, LOG_DEBUG))
    {
        LiveTVChainEntry e;
        GetEntryAt(num, e);
        QString msg = QString("%1_%2")
            .arg(e.chanid).arg(e.starttime.toString("yyyyMMddhhmmss"));
        LOG(VB_PLAYBACK, LOG_DEBUG,
            LOC + QString("Entry@%1: '%2')").arg(num).arg(msg));
    }
}
Пример #3
0
bool MSqlQuery::next()
{
    bool result = QSqlQuery::next();

    if (result && VERBOSE_LEVEL_CHECK(VB_DATABASE|VB_EXTRA))
    {
        QString str;
        QSqlRecord record=QSqlQuery::record();

        for ( long int i = 0; i<record.count(); i++ )
        {
            if (!str.isEmpty())
                str.append(", ");

            str.append(record.fieldName(i) + " = " + value(i).toString());
        }

        LOG(VB_DATABASE, LOG_DEBUG,
                QString("MSqlQuery::next(%1) Result: \"%2\"")
                        .arg(m_db->MSqlDatabase::GetConnectionName())
                        .arg(str));
    }

    return result;
}
Пример #4
0
bool MSqlQuery::seekDebug(const char *type, bool result,
                          int where, bool relative) const
{
    if (result && VERBOSE_LEVEL_CHECK(VB_DATABASE, LOG_DEBUG))
    {
        QString str;
        QSqlRecord rec = record();

        for (long int i = 0; i < rec.count(); i++)
        {
            if (!str.isEmpty())
                str.append(", ");

            str.append(rec.fieldName(i) + " = " +
                       value(i).toString());
        }

        if (QString("seek")==type)
        {
            LOG(VB_DATABASE, LOG_DEBUG,
                QString("MSqlQuery::seek(%1,%2,%3) Result: \"%4\"")
                .arg(m_db->MSqlDatabase::GetConnectionName())
                .arg(where).arg(relative)
                .arg(str));
        }
        else
        {
            LOG(VB_DATABASE, LOG_DEBUG,
                QString("MSqlQuery::%1(%2) Result: \"%3\"")
                .arg(type).arg(m_db->MSqlDatabase::GetConnectionName())
                .arg(str));
        }
    }
    return result;
}
Пример #5
0
/** \fn LiveTVChain::SwitchTo(int)
 *  \brief Sets the recording to switch to.
 *  \param num Index of recording to switch to, -1 for last recording.
 */
void LiveTVChain::SwitchTo(int num)
{
    QMutexLocker lock(&m_lock);

    VERBOSE(VB_PLAYBACK, LOC + "SwitchTo("<<num<<")");

    int size = m_chain.count();
    if ((num < 0) || (num >= size))
        num = size - 1;

    if (m_curpos != num)
    {
        m_switchid = num;
        GetEntryAt(num, m_switchentry);
    }
    else
        VERBOSE(VB_IMPORTANT, LOC + "SwitchTo() not switching to current");

    if (VERBOSE_LEVEL_CHECK(VB_PLAYBACK))
    {
        LiveTVChainEntry e;
        GetEntryAt(num, e);
        QString msg = QString("%1_%2")
            .arg(e.chanid).arg(e.starttime.toString("yyyyMMddhhmmss"));
        VERBOSE(VB_PLAYBACK, LOC + "Entry@"<<num<<": '"<<msg<<"'");
    }
}
Пример #6
0
bool MSqlQuery::exec()
{
    // Database connection down.  Try to restart it, give up if it's still
    // down
    if (!m_db)
    {
        // Database structure's been deleted
        return false;
    }

    if (!m_db->isOpen() && !m_db->Reconnect())
    {
        LOG(VB_GENERAL, LOG_INFO, "MySQL server disconnected");
        return false;
    }

    bool result = QSqlQuery::exec();

    // if the query failed with "MySQL server has gone away"
    // Close and reopen the database connection and retry the query if it
    // connects again
    if (!result && QSqlQuery::lastError().number() == 2006 && m_db->Reconnect())
        result = QSqlQuery::exec();

    if (VERBOSE_LEVEL_CHECK(VB_DATABASE) && logLevel <= LOG_DEBUG)
    {
        QString str = lastQuery();

        // Database logging will cause an infinite loop here if not filtered
        // out
        if (!str.startsWith("INSERT INTO logging "))
        {
       	    // Sadly, neither executedQuery() nor lastQuery() display
            // the values in bound queries against a MySQL5 database.
            // So, replace the named placeholders with their values.

            QMapIterator<QString, QVariant> b = boundValues();
            while (b.hasNext())
            {
                b.next();
                str.replace(b.key(), '\'' + b.value().toString() + '\'');
            }

            LOG(VB_DATABASE, LOG_DEBUG,
                QString("MSqlQuery::exec(%1) %2%3")
                        .arg(m_db->MSqlDatabase::GetConnectionName()).arg(str)
                        .arg(isSelect() ? QString(" <<<< Returns %1 row(s)")
                                              .arg(size()) : QString()));
        }
    }

    return result;
}
Пример #7
0
void SSDPCache::Dump()
{
    int nCount = 0;

    if (VERBOSE_LEVEL_CHECK(VB_UPNP))
    {

        Lock();

        // ----------------------------------------------------------------------
        // Build List of items to be removed
        // ----------------------------------------------------------------------

        VERBOSE( VB_UPNP, "===============================================================================" );
        VERBOSE( VB_UPNP, QString(  " URI (type) - Found: %1 Entries - %2 have been Allocated. " )
                             .arg( m_cache.count() )
                             .arg( SSDPCacheEntries::g_nAllocated ));
        VERBOSE( VB_UPNP, "   \t\tUSN (unique id)\t\t | Expires\t | Location" );
        VERBOSE( VB_UPNP, "-------------------------------------------------------------------------------" );

        for (SSDPCacheEntriesMap::Iterator it  = m_cache.begin();
                                           it != m_cache.end();
                                         ++it )
        {
            SSDPCacheEntries *pEntries = *it;

            if (pEntries != NULL)
            {
                VERBOSE( VB_UPNP, it.key() );

                pEntries->Lock();

                EntryMap *pMap = pEntries->GetEntryMap();

                for (EntryMap::Iterator itEntry  = pMap->begin();
                                        itEntry != pMap->end();
                                      ++itEntry )
                {

                    DeviceLocation *pEntry = *itEntry;

                    if (pEntry != NULL)
                    {
                        nCount++;

                        pEntry->AddRef();

                        VERBOSE( VB_UPNP, QString( " * \t\t%1\t | %2\t | %3 " ) 
                                             .arg( pEntry->m_sUSN )
                                             .arg( pEntry->ExpiresInSecs() )
                                             .arg( pEntry->m_sLocation ));

                        pEntry->Release();
                    }
                }

                VERBOSE( VB_UPNP, " "); 

                pEntries->Unlock();
            }
        }

        VERBOSE( VB_UPNP, "-------------------------------------------------------------------------------" );
        VERBOSE( VB_UPNP, QString(  " Found: %1 Entries - %2 have been Allocated. " )
                             .arg( nCount )
                             .arg( DeviceLocation::g_nAllocated ));
        VERBOSE( VB_UPNP, "===============================================================================" );

        Unlock();
    }
}
Пример #8
0
bool MSqlQuery::exec()
{
    if (!m_db)
    {
        // Database structure's been deleted
        return false;
    }

    if (m_last_prepared_query.isEmpty())
    {
        LOG(VB_GENERAL, LOG_ERR,
            "MSqlQuery::exec(void) called without a prepared query.");
        return false;
    }

#if DEBUG_RECONNECT
    if (random() < RAND_MAX / 50)
    {
        LOG(VB_GENERAL, LOG_INFO,
            "MSqlQuery disconnecting DB to test reconnection logic");
        m_db->m_db.close();
    }
#endif

    // Database connection down.  Try to restart it, give up if it's still
    // down
    if (!m_db->isOpen() && !Reconnect())
    {
        LOG(VB_GENERAL, LOG_INFO, "MySQL server disconnected");
        return false;
    }

    QElapsedTimer timer;
    timer.start();

    bool result = QSqlQuery::exec();
    qint64 elapsed = timer.elapsed();

    // if the query failed with "MySQL server has gone away"
    // Close and reopen the database connection and retry the query if it
    // connects again
    if (!result && QSqlQuery::lastError().number() == 2006 && Reconnect())
        result = QSqlQuery::exec();

    if (!result)
    {
        QString err = MythDB::GetError("MSqlQuery", *this);
        MSqlBindings tmp = QSqlQuery::boundValues();
        bool has_null_strings = false;
        for (MSqlBindings::iterator it = tmp.begin(); it != tmp.end(); ++it)
        {
            if (it->type() != QVariant::String)
                continue;
            if (it->isNull() || it->toString().isNull())
            {
                has_null_strings = true;
                *it = QVariant(QString(""));
            }
        }
        if (has_null_strings)
        {
            bindValues(tmp);
            timer.restart();
            result = QSqlQuery::exec();
            elapsed = timer.elapsed();
        }
        if (result)
        {
            LOG(VB_GENERAL, LOG_ERR,
                QString("Original query failed, but resend with empty "
                        "strings in place of NULL strings worked. ") +
                "\n" + err);
        }
    }

    if (VERBOSE_LEVEL_CHECK(VB_DATABASE, LOG_INFO))
    {
        QString str = lastQuery();

        // Database logging will cause an infinite loop here if not filtered
        // out
        if (!str.startsWith("INSERT INTO logging "))
        {
            // Sadly, neither executedQuery() nor lastQuery() display
            // the values in bound queries against a MySQL5 database.
            // So, replace the named placeholders with their values.

            QMapIterator<QString, QVariant> b = boundValues();
            while (b.hasNext())
            {
                b.next();
                str.replace(b.key(), '\'' + b.value().toString() + '\'');
            }

            LOG(VB_DATABASE, LOG_INFO,
                QString("MSqlQuery::exec(%1) %2%3%4")
                        .arg(m_db->MSqlDatabase::GetConnectionName()).arg(str)
                        .arg(QString(" <<<< Took %1ms").arg(QString::number(elapsed)))
                        .arg(isSelect() ? QString(", Returned %1 row(s)")
                                              .arg(size()) : QString()));
        }
    }

    return result;
}
Пример #9
0
bool AudioInputALSA::PrepHwParams(void)
{
    snd_pcm_hw_params_t* hwparams;
    snd_pcm_hw_params_alloca(&hwparams);
    if (AlsaBad(snd_pcm_hw_params_any(pcm_handle, hwparams),
                "failed to init hw params"))
        return false;
    snd_pcm_access_t axs = SND_PCM_ACCESS_RW_INTERLEAVED; //always?
    if (AlsaBad(snd_pcm_hw_params_set_access(pcm_handle, hwparams, axs),
                "failed to set interleaved rw io"))
        return false;
    snd_pcm_format_t format =
        (m_audio_sample_bits > 8) ? SND_PCM_FORMAT_S16 : SND_PCM_FORMAT_U8;
    if (AlsaBad(snd_pcm_hw_params_set_format(pcm_handle, hwparams, format),
                QString("failed to set sample format %1")
                .arg(snd_pcm_format_description(format))))
        return false;
    if (VERBOSE_LEVEL_CHECK(VB_AUDIO, LOG_DEBUG))
    {
        uint min_chans, max_chans;
        if(AlsaBad(snd_pcm_hw_params_get_channels_min(hwparams, &min_chans),
                   QString("unable to get min channel count")))
            min_chans = 0;
        if(AlsaBad(snd_pcm_hw_params_get_channels_max(hwparams, &max_chans),
                   QString("unable to get max channel count")))
            max_chans = 0;
        LOG(VB_AUDIO, LOG_DEBUG, LOC_DEV +
            QString("min channels %1, max channels %2, myth requests %3")
            .arg(min_chans).arg(max_chans).arg(m_audio_channels));
    }
    if (AlsaBad(snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
                m_audio_channels), QString("failed to set channels to %1")
                .arg(m_audio_channels)))
    {
        return false;
    }
    if (AlsaBad(snd_pcm_hw_params_set_rate(pcm_handle, hwparams,
                                           m_audio_sample_rate, 0), QString("failed to set sample rate %1")
                .arg(m_audio_sample_rate)))
    {
        uint rate_num = 0;
        uint rate_den = 0;
        if (!AlsaBad(snd_pcm_hw_params_get_rate_numden(hwparams, &rate_num,
                     &rate_den), "snd_pcm_hw_params_get_rate_numden failed"))
            if (m_audio_sample_rate != (int)(rate_num / rate_den))
                LOG(VB_GENERAL, LOG_ERR, LOC_DEV +
                    QString("device reports sample rate as %1")
                    .arg(rate_num / rate_den));
        return false;
    }
    uint buffer_time = 64000; // 64 msec
    uint period_time = buffer_time / 4;
    if (AlsaBad(snd_pcm_hw_params_set_period_time_near(pcm_handle, hwparams, &period_time, NULL),
                "failed to set period time"))
        return false;
    if (AlsaBad(snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams, &buffer_time, NULL),
                "failed to set buffer time"))
        return false;
    if (AlsaBad(snd_pcm_hw_params_get_period_size(hwparams, &period_size, NULL),
                "failed to get period size"))
        return false;

    if (AlsaBad(snd_pcm_hw_params (pcm_handle, hwparams),
                "failed to set hwparams"))
        return false;

    myth_block_bytes = snd_pcm_frames_to_bytes(pcm_handle, period_size);
    LOG(VB_AUDIO, LOG_INFO, LOC_DEV +
        QString("channels %1, sample rate %2, buffer_time %3 msec, period "
                "size %4").arg(m_audio_channels)
        .arg(m_audio_sample_rate).arg(buffer_time / 1000.0, -1, 'f', 1)
        .arg(period_size));
    LOG(VB_AUDIO, LOG_DEBUG, LOC_DEV + QString("myth block size %1")
        .arg(myth_block_bytes));
    return true;
}
Пример #10
0
void ChannelScannerCLI::HandleEvent(const ScannerEvent *scanEvent)
{
    if ((scanEvent->type() == ScannerEvent::ScanComplete) ||
        (scanEvent->type() == ScannerEvent::ScanShutdown))
    {
        cout<<endl;

        if (scanEvent->type() == ScannerEvent::ScanShutdown)
            cerr<<"HandleEvent(void) -- scan shutdown"<<endl;
        else
            cerr<<"HandleEvent(void) -- scan complete"<<endl;

        ScanDTVTransportList transports;
        if (sigmonScanner)
        {
            sigmonScanner->StopScanner();
            transports = sigmonScanner->GetChannelList();
        }

        Teardown();

        if (!transports.empty())
            Process(transports);

        done = true;
        QCoreApplication::exit(0);
    }
    else if (scanEvent->type() == ScannerEvent::AppendTextToLog)
        status_last_log = scanEvent->strValue();
    else if (scanEvent->type() == ScannerEvent::SetStatusText)
        status_text = scanEvent->strValue();
    else if (scanEvent->type() == ScannerEvent::SetStatusTitleText)
        ;
    else if (scanEvent->type() == ScannerEvent::SetPercentComplete)
        status_complete = scanEvent->intValue();
    else if (scanEvent->type() == ScannerEvent::SetStatusRotorPosition)
        ;
    else if (scanEvent->type() == ScannerEvent::SetStatusSignalLock)
        status_lock = scanEvent->intValue();
    else if (scanEvent->type() == ScannerEvent::SetStatusSignalToNoise)
        status_snr = scanEvent->intValue() / 65535.0;
    else if (scanEvent->type() == ScannerEvent::SetStatusSignalStrength)
        ;

    //cout<<"HERE<"<<print_verbose_messages<<">"<<endl;
    QString msg;
    if (VERBOSE_LEVEL_NONE || VERBOSE_LEVEL_CHECK(VB_CHANSCAN))
    {
        msg.sprintf("%3i%% S/N %3.1f %s : %s (%s) %20s",
                    status_complete, status_snr,
                    (status_lock) ? "l" : "L",
                    status_text.toAscii().constData(),
                    status_last_log.toAscii().constData(), "");
    }
    //cout<<msg.toAscii().constData()<<endl;

    if (VERBOSE_LEVEL_CHECK(VB_CHANSCAN))
    {
        static QString old_msg;
        if (msg != old_msg)
        {
            VERBOSE(VB_CHANSCAN, LOC + msg);
            old_msg = msg;
        }
    }
    else if (VERBOSE_LEVEL_NONE)
    {
        if (msg.length() > 80)
            msg = msg.left(77) + "...";
        cout<<"\r"<<msg.toAscii().constData()<<"\r";
        cout<<flush;
    }
}
Пример #11
0
/**
 *  \brief Tunes the card to a frequency but does not deal with PIDs.
 *
 *   This is used by DVB Channel Scanner, the EIT Parser, and by TVRec.
 *
 *  \param tuning      Info on transport to tune to
 *  \param inputid     Optional, forces specific input (for DiSEqC)
 *  \param force_reset If true, frequency tuning is done
 *                     even if it should not be needed.
 *  \param same_input  Optional, doesn't change input (for retuning).
 *  \return true on success, false on failure
 */
bool DVBChannel::Tune(const DTVMultiplex &tuning,
                      uint inputid,
                      bool force_reset,
                      bool same_input)
{
    QMutexLocker lock(&tune_lock);
    QMutexLocker locker(&hw_lock);

    DVBChannel *master = GetMasterLock();
    if (master != this)
    {
        LOG(VB_CHANNEL, LOG_INFO, LOC + "tuning on slave channel");
        SetSIStandard(tuning.sistandard);
        bool ok = master->Tune(tuning, inputid, force_reset, false);
        ReturnMasterLock(master);
        return ok;
    }
    ReturnMasterLock(master); // if we're the master we don't need this lock..


    int intermediate_freq = 0;
    bool can_fec_auto = false;
    bool reset = (force_reset || first_tune);

    if (tunerType.IsDiSEqCSupported() && !diseqc_tree)
    {
        LOG(VB_GENERAL, LOG_ERR, LOC +
            "DVB-S needs device tree for LNB handling");
        return false;
    }

    desired_tuning = tuning;

    if (fd_frontend < 0)
    {
        LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): Card not open!");

        return false;
    }

    // Remove any events in queue before tuning.
    drain_dvb_events(fd_frontend);

    // send DVB-S setup
    if (diseqc_tree)
    {
        // configure for new input
        if (!same_input)
            diseqc_settings.Load(inputid);

        // execute diseqc commands
        if (!diseqc_tree->Execute(diseqc_settings, tuning))
        {
            LOG(VB_GENERAL, LOG_ERR, LOC +
                "Tune(): Failed to setup DiSEqC devices");
            return false;
        }

        // retrieve actual intermediate frequency
        DiSEqCDevLNB *lnb = diseqc_tree->FindLNB(diseqc_settings);
        if (!lnb)
        {
            LOG(VB_GENERAL, LOG_ERR, LOC +
                "Tune(): No LNB for this configuration");
            return false;
        }

        if (lnb->GetDeviceID() != last_lnb_dev_id)
        {
            last_lnb_dev_id = lnb->GetDeviceID();
            // make sure we tune to frequency, if the lnb has changed
            reset = first_tune = true;
        }

        intermediate_freq = lnb->GetIntermediateFrequency(
            diseqc_settings, tuning);

        // if card can auto-FEC, use it -- sometimes NITs are inaccurate
        if (capabilities & FE_CAN_FEC_AUTO)
            can_fec_auto = true;

        // Check DVB-S intermediate frequency here since it requires a fully
        // initialized diseqc tree
        CheckFrequency(intermediate_freq);
    }

    LOG(VB_CHANNEL, LOG_INFO, LOC + "Old Params: " + prev_tuning.toString() +
            "\n\t\t\t" + LOC + "New Params: " + tuning.toString());

    // DVB-S is in kHz, other DVB is in Hz
    bool is_dvbs = ((DTVTunerType::kTunerTypeDVBS1 == tunerType) ||
                    (DTVTunerType::kTunerTypeDVBS2 == tunerType));
    int     freq_mult = (is_dvbs) ? 1 : 1000;
    QString suffix    = (is_dvbs) ? "kHz" : "Hz";

    if (reset || !prev_tuning.IsEqual(tunerType, tuning, 500 * freq_mult))
    {
        LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Tune(): Tuning to %1%2")
                .arg(intermediate_freq ? intermediate_freq : tuning.frequency)
                .arg(suffix));

#if DVB_API_VERSION >=5
        if (DTVTunerType::kTunerTypeDVBS2 == tunerType)
        {
            struct dtv_property p_clear;
            struct dtv_properties cmdseq_clear;

            p_clear.cmd        = DTV_CLEAR;
            cmdseq_clear.num   = 1;
            cmdseq_clear.props = &p_clear;

            if ((ioctl(fd_frontend, FE_SET_PROPERTY, &cmdseq_clear)) < 0)
            {
                LOG(VB_GENERAL, LOG_ERR, LOC +
                    "Tune(): Clearing DTV properties cache failed." + ENO);
                return false;
            }

            struct dtv_properties *cmds = dtvmultiplex_to_dtvproperties(
                tunerType, tuning, intermediate_freq, can_fec_auto);

            if (!cmds) {
                LOG(VB_GENERAL, LOG_ERR, LOC +
                    "Failed to convert DTVMultiplex to DTV_PROPERTY sequence");
                return false;
            }

            if (VERBOSE_LEVEL_CHECK(VB_CHANNEL, LOG_DEBUG))
            {
                for (uint i = 0; i < cmds->num; i++)
                {
                    LOG(VB_CHANNEL, LOG_DEBUG, LOC +
                        QString("prop %1: cmd = %2, data %3")
                            .arg(i).arg(cmds->props[i].cmd)
                            .arg(cmds->props[i].u.data));
                }
            }

            int res = ioctl(fd_frontend, FE_SET_PROPERTY, cmds);

            free(cmds->props);
            free(cmds);

            if (res < 0)
            {
                LOG(VB_GENERAL, LOG_ERR, LOC +
                    "Tune(): Setting Frontend tuning parameters failed." + ENO);
                return false;
            }
        }
        else
#endif
        {
            struct dvb_frontend_parameters params = dtvmultiplex_to_dvbparams(
                tunerType, tuning, intermediate_freq, can_fec_auto);

            if (ioctl(fd_frontend, FE_SET_FRONTEND, &params) < 0)
            {
                LOG(VB_GENERAL, LOG_ERR, LOC +
                    "Tune(): Setting Frontend tuning parameters failed." + ENO);
                return false;
            }
        }

        // Extra delay to add for broken DVB drivers
        if (tuning_delay)
            usleep(tuning_delay * 1000);

        wait_for_backend(fd_frontend, 5 /* msec */);

        prev_tuning = tuning;
        first_tune = false;
    }

    SetSIStandard(tuning.sistandard);

    LOG(VB_CHANNEL, LOG_INFO, LOC + "Tune(): Frequency tuning successful.");

    return true;
}
Пример #12
0
    static MythImage *LoadImage(MythPainter *painter,
                                 // Must be a copy for thread safety
                                ImageProperties imProps,
                                ImageCacheMode cacheMode,
                                 // Included only to check address, could be
                                 // replaced by generating a unique value for
                                 // each MythUIImage object?
                                const MythUIImage *parent,
                                bool &aborted,
                                MythImageReader *imageReader = NULL)
    {
        QString cacheKey = GenImageLabel(imProps);
        if (!PreLoad(cacheKey, parent))
        {
            aborted = true;
            return NULL;
        }

        QString filename = imProps.filename;
        MythImage *image = NULL;

        bool bResize = false;
        bool bFoundInCache = false;

        int w = -1;
        int h = -1;

        if (!imProps.forceSize.isNull())
        {
            if (imProps.forceSize.width() != -1)
                w = imProps.forceSize.width();

            if (imProps.forceSize.height() != -1)
                h = imProps.forceSize.height();

            bResize = true;
        }

        if (!imageReader)
        {
            image = GetMythUI()->LoadCacheImage(filename, cacheKey,
                                                painter, cacheMode);
        }

        if (image)
        {
            if (VERBOSE_LEVEL_CHECK(VB_GUI | VB_FILE, LOG_INFO))
            {
                image->IncrRef();
                int cnt = image->DecrRef();
                LOG(VB_GUI | VB_FILE, LOG_INFO,
                    QString("ImageLoader::LoadImage(%1) Found in cache, "
                            "RefCount = %2")
                    .arg(cacheKey).arg(cnt));
            }

            if (imProps.isReflected)
                image->setIsReflected(true);

            if (imProps.isOriented)
                image->setIsOriented(true);

            bFoundInCache = true;
        }
        else
        {
            LOG(VB_GUI | VB_FILE, LOG_INFO,
                QString("ImageLoader::LoadImage(%1) NOT Found in cache. "
                        "Loading Directly").arg(cacheKey));

            image = painter->GetFormatImage();
            bool ok = false;

            if (imageReader)
                ok = image->Load(imageReader);
            else
                ok = image->Load(filename);

            if (!ok)
            {
                image->DecrRef();
                image = NULL;
            }
        }

        if (image && image->isNull())
        {
            LOG(VB_GUI | VB_FILE, LOG_INFO,
                QString("ImageLoader::LoadImage(%1) Image is NULL")
                                                    .arg(filename));

            image->DecrRef();
            image = NULL;
        }

        if (image && !bFoundInCache)
        {
            if (imProps.isReflected)
                image->Reflect(imProps.reflectAxis, imProps.reflectShear,
                               imProps.reflectScale, imProps.reflectLength,
                               imProps.reflectSpacing);

            if (imProps.isGreyscale)
                image->ToGreyscale();

            if (imProps.isOriented)
                image->Orientation(imProps.orientation);

            // Even if an explicit size wasn't defined this image may still need
            // to be scaled because of a difference between the theme resolution
            // and the screen resolution. We want to avoid scaling twice.
            if (!bResize && imProps.isThemeImage)
            {
                float wmult; // Width multipler
                float hmult; // Height multipler
                GetMythUI()->GetScreenSettings(wmult, hmult);
                if (wmult != 1.0f || hmult != 1.0f)
                {
                    w = image->size().width() * wmult;
                    h = image->size().height() * hmult;
                    bResize = true;
                }
            }

            if (bResize)
                image->Resize(QSize(w, h), imProps.preserveAspect);

            if (imProps.isMasked)
            {
                QRect imageArea = image->rect();
                QRect maskArea = imProps.GetMaskImageRect();

                // Crop the mask to the image
                int x = 0;
                int y = 0;

                if (maskArea.width() > imageArea.width())
                    x = (maskArea.width() - imageArea.width()) / 2;

                if (maskArea.height() > imageArea.height())
                    y = (maskArea.height() - imageArea.height()) / 2;

                if (x > 0 || y > 0)
                    imageArea.translate(x, y);

                QImage mask = imProps.GetMaskImageSubset(imageArea);
                image->setAlphaChannel(mask.alphaChannel());
            }

            if (!imageReader)
                GetMythUI()->CacheImage(cacheKey, image);
        }

        if (image)
            image->SetChanged();

        PostLoad(cacheKey);

        return image;
    }
Пример #13
0
void MythSocketThread::run(void)
{
    VERBOSE(VB_SOCKET, "MythSocketThread: readyread thread start");

    QMutexLocker locker(&m_readyread_lock);
    m_readyread_started_wait.wakeAll();
    while (m_readyread_run)
    {
        VERBOSE(VB_SOCKET|VB_EXTRA, "ProcessAddRemoveQueues");

        ProcessAddRemoveQueues();

        VERBOSE(VB_SOCKET|VB_EXTRA, "Construct FD_SET");

        // construct FD_SET for all connected and unlocked sockets...
        int maxfd = -1;
        fd_set rfds;
        FD_ZERO(&rfds);

        QList<MythSocket*>::const_iterator it = m_readyread_list.begin();
        for (; it != m_readyread_list.end(); ++it)
        {
            if (!(*it)->TryLock(false))
                continue;

            if ((*it)->state() == MythSocket::Connected &&
                !(*it)->m_notifyread)
            {
                FD_SET((*it)->socket(), &rfds);
                maxfd = std::max((*it)->socket(), maxfd);
            }
            (*it)->Unlock(false);
        }

        // There are no unlocked sockets, wait for event before we continue..
        if (maxfd < 0)
        {
            VERBOSE(VB_SOCKET|VB_EXTRA, "Empty FD_SET, sleeping");
            if (m_readyread_wait.wait(&m_readyread_lock))
                VERBOSE(VB_SOCKET|VB_EXTRA, "Empty FD_SET, woken up");
            else
                VERBOSE(VB_SOCKET|VB_EXTRA, "Empty FD_SET, timed out");
            continue;
        }

        int rval = 0;

        if (m_readyread_pipe[0] >= 0)
        {
            // Clear out any pending pipe reads, we have already taken care of
            // this event above under the m_readyread_lock.
            char dummy[128];
            if (m_readyread_pipe_flags[0] & O_NONBLOCK)
            {
                rval = ::read(m_readyread_pipe[0], dummy, 128);
                FD_SET(m_readyread_pipe[0], &rfds);
                maxfd = std::max(m_readyread_pipe[0], maxfd);
            }

            // also exit select on exceptions on same descriptors
            fd_set efds;
            memcpy(&efds, &rfds, sizeof(fd_set));

            // The select waits forever for data, so if we need to process
            // anything else we need to write to m_readyread_pipe[1]..
            // We unlock the ready read lock, because we don't need it
            // and this will allow WakeReadyReadThread() to run..
            m_readyread_lock.unlock();
            VERBOSE(VB_SOCKET|VB_EXTRA, "Waiting on select..");
            rval = select(maxfd + 1, &rfds, NULL, &efds, NULL);
            VERBOSE(VB_SOCKET|VB_EXTRA, "Got data on select");
            m_readyread_lock.lock();

            if (rval > 0 && FD_ISSET(m_readyread_pipe[0], &rfds))
            {
                int ret = ::read(m_readyread_pipe[0], dummy, 128);
                if (ret < 0)
                {
                    VERBOSE(VB_SOCKET|VB_EXTRA,
                            "Strange.. failed to read event pipe");
                }
            }
        }
        else
        {
            VERBOSE(VB_SOCKET|VB_EXTRA, "Waiting on select.. (no pipe)");

            // also exit select on exceptions on same descriptors
            fd_set efds;
            memcpy(&efds, &rfds, sizeof(fd_set));

            // Unfortunately, select on a pipe is not supported on all
            // platforms. So we fallback to a loop that instead times out
            // of select and checks for wakeAll event.
            while (!rval)
            {
                struct timeval timeout;
                timeout.tv_sec = 0;
                timeout.tv_usec = kShortWait * 1000;
                rval = select(maxfd + 1, &rfds, NULL, &efds, &timeout);
                if (!rval)
                    m_readyread_wait.wait(&m_readyread_lock, kShortWait);
            }

            VERBOSE(VB_SOCKET|VB_EXTRA, "Got data on select (no pipe)");
        }

        if (rval <= 0)
        {
            if (rval == 0)
            {
                // Note: This should never occur when using pipes. When there
                // is no error there should be data in at least one fd..
                VERBOSE(VB_SOCKET|VB_EXTRA, "MythSocketThread: select timeout");
            }
            else
                VERBOSE(VB_SOCKET,
                        "MythSocketThread: select returned error" + ENO);

            m_readyread_wait.wait(&m_readyread_lock, kShortWait);
            continue;
        }
        
        // ReadyToBeRead allows calls back into the socket so we need
        // to release the lock for a little while.
        // since only this loop updates m_readyread_list this is safe.
        m_readyread_lock.unlock();

        // Actually read some data! This is a form of co-operative
        // multitasking so the ready read handlers should be quick..

        uint downref_tm = 0;
        if (!m_readyread_downref_list.empty())
        {
            VERBOSE(VB_SOCKET|VB_EXTRA, "Deleting stale sockets");

            QTime tm = QTime::currentTime();
            for (it = m_readyread_downref_list.begin();
                 it != m_readyread_downref_list.end(); ++it)
            {
                (*it)->DownRef();
            }
            m_readyread_downref_list.clear();
            downref_tm = tm.elapsed();
        }

        VERBOSE(VB_SOCKET|VB_EXTRA, "Processing ready reads");

        QMap<uint,uint> timers;
        QTime tm = QTime::currentTime();
        it = m_readyread_list.begin();

        for (; it != m_readyread_list.end() && m_readyread_run; ++it)
        {
            if (!(*it)->TryLock(false))
                continue;
            
            int socket = (*it)->socket();

            if (socket >= 0 &&
                (*it)->state() == MythSocket::Connected &&
                FD_ISSET(socket, &rfds))
            {
                QTime rrtm = QTime::currentTime();
                ReadyToBeRead(*it);
                timers[socket] = rrtm.elapsed();
            }
            (*it)->Unlock(false);
        }

        if (VERBOSE_LEVEL_CHECK(VB_SOCKET|VB_EXTRA))
        {
            QString rep = QString("Total read time: %1ms, on sockets")
                .arg(tm.elapsed());
            QMap<uint,uint>::const_iterator it = timers.begin();
            for (; it != timers.end(); ++it)
                rep += QString(" {%1,%2ms}").arg(it.key()).arg(*it);
            if (downref_tm)
                rep += QString(" {downref, %1ms}").arg(downref_tm);

            VERBOSE(VB_SOCKET|VB_EXTRA, QString("MythSocketThread: ") + rep);
        }

        m_readyread_lock.lock();
        VERBOSE(VB_SOCKET|VB_EXTRA, "Reacquired ready read lock");
    }

    VERBOSE(VB_SOCKET, "MythSocketThread: readyread thread exit");
}
Пример #14
0
bool MythSocket::writeStringList(QStringList &list)
{
    if (list.size() <= 0)
    {
        VERBOSE(VB_IMPORTANT, LOC +
                "writeStringList: Error, invalid string list.");
        return false;
    }

    if (state() != Connected)
    {
        VERBOSE(VB_IMPORTANT, LOC +
                "writeStringList: Error, called with unconnected socket.");
        return false;
    }

    QString str = list.join("[]:[]");
    if (str.isEmpty())
    {
        VERBOSE(VB_IMPORTANT, LOC +
                "writeStringList: Error, joined null string.");
        return false;
    }

    QByteArray utf8 = str.toUtf8();
    int size = utf8.length();
    int written = 0;
    int written_since_timer_restart = 0;

    QByteArray payload;
    payload = payload.setNum(size);
    payload += "        ";
    payload.truncate(8);
    payload += utf8;
    size = payload.length();

    if (VERBOSE_LEVEL_CHECK(VB_NETWORK))
    {
        QString msg = QString("write -> %1 %2")
            .arg(socket(), 2).arg(payload.data());

        if (!VERBOSE_LEVEL_CHECK(VB_EXTRA) && msg.length() > 88)
        {
            msg.truncate(85);
            msg += "...";
        }
        VERBOSE(VB_NETWORK, LOC + msg);
    }

    MythTimer timer; timer.start();
    unsigned int errorcount = 0;
    while (size > 0)
    {
        if (state() != Connected)
        {
            VERBOSE(VB_IMPORTANT, LOC +
                    "writeStringList: Error, socket went unconnected." +
                    QString("\n\t\t\tWe wrote %1 of %2 bytes with %3 errors")
                    .arg(written).arg(written+size).arg(errorcount) +
                    QString("\n\t\t\tstarts with: %1").arg(toSample(payload)));
            return false;
        }

        int temp = writeBlock(payload.data() + written, size);
        if (temp > 0)
        {
            written += temp;
            written_since_timer_restart += temp;
            size -= temp;
            if ((timer.elapsed() > 500) && written_since_timer_restart != 0)
            {
                timer.restart();
                written_since_timer_restart = 0;
            }
        }
        else if (temp < 0 && error() != MSocketDevice::NoError)
        {
            VERBOSE(VB_IMPORTANT, LOC +
                    QString("writeStringList: Error, writeBlock failed. (%1)")
                    .arg(errorToString()));
            return false;
        }
        else if (temp <= 0)
        {
            errorcount++;
            if (timer.elapsed() > 1000)
            {
                VERBOSE(VB_GENERAL, LOC + "writeStringList: Error, " +
                        QString("No data written on writeBlock (%1 errors)")
                        .arg(errorcount) +
                        QString("\n\t\t\tstarts with: %1")
                        .arg(toSample(payload)));
                return false;
            }
            usleep(1000);
        }
    }

    flush();

    return true;
}
Пример #15
0
// pure virtual
bool CdDecoder::initialize()
{
    if (m_inited)
        return true;

    m_inited = m_user_stop = m_finish = false;
    m_freq = m_bitrate = 0L;
    m_stat = DecoderEvent::Error;
    m_chan = 0;
    m_seekTime = -1.;

    if (output())
        output()->PauseUntilBuffered();

    QFile* file = dynamic_cast< QFile* >(input()); // From QIODevice*
    if (file)
    {
        setFilename(file->fileName());
        m_tracknum = getFilename().section('.', 0, 0).toUInt();
    }

    QMutexLocker lock(&getCdioMutex());

    m_cdio = openCdio(m_devicename);
    if (!m_cdio)
        return false;

    m_start = cdio_get_track_lsn(m_cdio, m_tracknum);
    m_end = cdio_get_track_last_lsn(m_cdio, m_tracknum);
    if (CDIO_INVALID_LSN  == m_start ||
        CDIO_INVALID_LSN  == m_end)
    {
        LOG(VB_MEDIA, LOG_INFO, "CdDecoder: No tracks on " + m_devicename);
        cdio_destroy(m_cdio), m_cdio = 0;
        return false;
    }

    LOG(VB_MEDIA, LOG_DEBUG, QString("CdDecoder track=%1 lsn start=%2 end=%3")
            .arg(m_tracknum).arg(m_start).arg(m_end));
    m_curpos = m_start;

    m_device = cdio_cddap_identify_cdio(m_cdio, 0, NULL);
    if (NULL == m_device)
    {
        LOG(VB_GENERAL, LOG_ERR,
            QString("Error: CdDecoder: cdio_cddap_identify(%1) failed")
                .arg(m_devicename));
        cdio_destroy(m_cdio), m_cdio = 0;
        return false;
    }

    cdio_cddap_verbose_set(m_device,
        VERBOSE_LEVEL_CHECK(VB_MEDIA, LOG_ANY) ? CDDA_MESSAGE_PRINTIT :
            CDDA_MESSAGE_FORGETIT,
        VERBOSE_LEVEL_CHECK(VB_MEDIA, LOG_DEBUG) ? CDDA_MESSAGE_PRINTIT :
            CDDA_MESSAGE_FORGETIT);

    if (DRIVER_OP_SUCCESS == cdio_cddap_open(m_device))
    {
        // cdio_get_track_last_lsn is unreliable on discs with data at end
        lsn_t end2 = cdio_cddap_track_lastsector(m_device, m_tracknum);
        if (end2 < m_end)
        {
            LOG(VB_MEDIA, LOG_INFO, QString("CdDecoder: trim last lsn from %1 to %2")
                .arg(m_end).arg(end2));
            m_end = end2;
        }

        m_paranoia = cdio_paranoia_init(m_device);
        if (NULL != m_paranoia)
        {
            cdio_paranoia_modeset(m_paranoia, PARANOIA_MODE_DISABLE);
            (void)cdio_paranoia_seek(m_paranoia, m_start, SEEK_SET);
        }
        else
        {
            LOG(VB_GENERAL, LOG_ERR, "Warn: CD reading with paranoia is disabled");
        }
    }
    else
    {
        LOG(VB_GENERAL, LOG_ERR,
            QString("Warn: drive '%1' is not cdda capable").
            arg(m_devicename));
    }

    int chnls = cdio_get_track_channels(m_cdio, m_tracknum);
    m_chan = chnls > 0 ? chnls : 2;
    m_freq = kSamplesPerSec;

    if (output())
    {
        const AudioSettings settings(FORMAT_S16, m_chan,
            CODEC_ID_PCM_S16LE, m_freq, false /* AC3/DTS passthru */);
        output()->Reconfigure(settings);
        output()->SetSourceBitrate(m_freq * m_chan * 16);
    }

    // 20ms worth
    m_bks = (m_freq * m_chan * 2) / 50;
    m_bksFrames = m_freq / 50;
    // decode 8 bks worth of samples each time we need more
    m_decodeBytes = m_bks << 3;

    m_output_buf = reinterpret_cast< char* >(
        ::av_malloc(m_decodeBytes + CDIO_CD_FRAMESIZE_RAW * 2));
    m_output_at = 0;

    setCDSpeed(2);
    m_inited = true;

    return m_inited;
}
Пример #16
0
void MythSocket::ReadStringListReal(
    QStringList *list, uint timeoutMS, bool *ret)
{
    list->clear();
    *ret = false;

    MythTimer timer;
    timer.start();
    int elapsed = 0;

    while (m_tcpSocket->bytesAvailable() < 8)
    {
        elapsed = timer.elapsed();
        if (elapsed >= (int)timeoutMS)
        {
            LOG(VB_GENERAL, LOG_ERR, LOC + "ReadStringList: " +
                QString("Error, timed out after %1 ms.").arg(timeoutMS));
            m_tcpSocket->close();
            m_dataAvailable.fetchAndStoreOrdered(0);
            return;
        }

        if (m_tcpSocket->state() != QAbstractSocket::ConnectedState)
        {
            LOG(VB_GENERAL, LOG_ERR, LOC + "ReadStringList: Connection died.");
            m_dataAvailable.fetchAndStoreOrdered(0);
            return;
        }

        m_tcpSocket->waitForReadyRead(50);
    }

    QByteArray sizestr(8 + 1, '\0');
    if (m_tcpSocket->read(sizestr.data(), 8) < 0)
    {
        LOG(VB_GENERAL, LOG_ERR, LOC +
            QString("ReadStringList: Error, read return error (%1)")
                .arg(m_tcpSocket->errorString()));
        m_tcpSocket->close();
        m_dataAvailable.fetchAndStoreOrdered(0);
        return;
    }

    QString sizes = sizestr;
    qint64 btr = sizes.trimmed().toInt();

    if (btr < 1)
    {
        int pending = m_tcpSocket->bytesAvailable();
        LOG(VB_GENERAL, LOG_ERR, LOC +
            QString("Protocol error: '%1' is not a valid size "
                    "prefix. %2 bytes pending.")
                .arg(sizestr.data()).arg(pending));
        ResetReal();
        return;
    }

    QByteArray utf8(btr + 1, 0);

    qint64 readoffset = 0;
    int errmsgtime = 0;
    timer.start();

    while (btr > 0)
    {
        if (m_tcpSocket->bytesAvailable() < 1)
        {
            if (m_tcpSocket->state() == QAbstractSocket::ConnectedState)
            {
                m_tcpSocket->waitForReadyRead(50);
            }
            else
            {
                LOG(VB_GENERAL, LOG_ERR, LOC +
                    "ReadStringList: Connection died.");
                m_dataAvailable.fetchAndStoreOrdered(0);
                return;
            }
        }

        qint64 sret = m_tcpSocket->read(utf8.data() + readoffset, btr);
        if (sret > 0)
        {
            readoffset += sret;
            btr -= sret;
            if (btr > 0)
            {
                timer.start();
            }
        }
        else if (sret < 0)
        {
            LOG(VB_GENERAL, LOG_ERR, LOC + "ReadStringList: Error, read");
            m_tcpSocket->close();
            m_dataAvailable.fetchAndStoreOrdered(0);
            return;
        }
        else if (!m_tcpSocket->isValid())
        {
            LOG(VB_GENERAL, LOG_ERR, LOC +
                "ReadStringList: Error, socket went unconnected");
            m_tcpSocket->close();
            m_dataAvailable.fetchAndStoreOrdered(0);
            return;
        }
        else
        {
            elapsed = timer.elapsed();
            if (elapsed  > 10000)
            {
                if ((elapsed - errmsgtime) > 10000)
                {
                    errmsgtime = elapsed;
                    LOG(VB_GENERAL, LOG_ERR, LOC +
                        QString("ReadStringList: Waiting for data: %1 %2")
                            .arg(readoffset).arg(btr));
                }
            }

            if (elapsed > 100000)
            {
                LOG(VB_GENERAL, LOG_ERR, LOC +
                    "Error, ReadStringList timeout (readBlock)");
                m_dataAvailable.fetchAndStoreOrdered(0);
                return;
            }
        }
    }

    QString str = QString::fromUtf8(utf8.data());

    QByteArray payload;
    payload = payload.setNum(str.length());
    payload += "        ";
    payload.truncate(8);
    payload += str;

    if (VERBOSE_LEVEL_CHECK(VB_NETWORK, LOG_INFO))
    {
        QString msg = QString("read  <- %1 %2")
            .arg(m_tcpSocket->socketDescriptor(), 2)
            .arg(payload.data());

        if (logLevel < LOG_DEBUG && msg.length() > 88)
        {
            msg.truncate(85);
            msg += "...";
        }
        LOG(VB_NETWORK, LOG_INFO, LOC + msg);
    }

    *list = str.split("[]:[]");

    m_dataAvailable.fetchAndStoreOrdered(
        (m_tcpSocket->bytesAvailable() > 0) ? 1 : 0);

    *ret = true;
}
Пример #17
0
void MythSocket::WriteStringListReal(const QStringList *list, bool *ret)
{
    if (list->empty())
    {
        LOG(VB_GENERAL, LOG_ERR, LOC +
            "WriteStringList: Error, invalid string list.");
        *ret = false;
        return;
    }

    if (m_tcpSocket->state() != QAbstractSocket::ConnectedState)
    {
        LOG(VB_GENERAL, LOG_ERR, LOC +
            "WriteStringList: Error, called with unconnected socket.");
        *ret = false;
        return;
    }

    QString str = list->join("[]:[]");
    if (str.isEmpty())
    {
        LOG(VB_GENERAL, LOG_ERR, LOC +
            "WriteStringList: Error, joined null string.");
        *ret = false;
        return;
    }

    QByteArray utf8 = str.toUtf8();
    int size = utf8.length();
    int written = 0;
    int written_since_timer_restart = 0;

    QByteArray payload;
    payload = payload.setNum(size);
    payload += "        ";
    payload.truncate(8);
    payload += utf8;
    size = payload.length();

    if (VERBOSE_LEVEL_CHECK(VB_NETWORK, LOG_INFO))
    {
        QString msg = QString("write -> %1 %2")
            .arg(m_tcpSocket->socketDescriptor(), 2).arg(payload.data());

        if (logLevel < LOG_DEBUG && msg.length() > 88)
        {
            msg.truncate(85);
            msg += "...";
        }
        LOG(VB_NETWORK, LOG_INFO, LOC + msg);
    }

    MythTimer timer; timer.start();
    unsigned int errorcount = 0;
    while (size > 0)
    {
        if (m_tcpSocket->state() != QAbstractSocket::ConnectedState)
        {
            LOG(VB_GENERAL, LOG_ERR, LOC +
                "WriteStringList: Error, socket went unconnected." +
                QString("\n\t\t\tWe wrote %1 of %2 bytes with %3 errors")
                    .arg(written).arg(written+size).arg(errorcount) +
                    QString("\n\t\t\tstarts with: %1").arg(to_sample(payload)));
            *ret = false;
            return;
        }

        int temp = m_tcpSocket->write(payload.data() + written, size);
        if (temp > 0)
        {
            written += temp;
            written_since_timer_restart += temp;
            size -= temp;
            if ((timer.elapsed() > 500) && written_since_timer_restart != 0)
            {
                timer.restart();
                written_since_timer_restart = 0;
            }
        }
        else if (temp <= 0)
        {
            errorcount++;
            if (timer.elapsed() > 1000)
            {
                LOG(VB_GENERAL, LOG_ERR, LOC + "WriteStringList: Error, " +
                    QString("No data written on write (%1 errors)")
                        .arg(errorcount) +
                    QString("\n\t\t\tstarts with: %1")
                    .arg(to_sample(payload)));
                *ret = false;
                return;
            }
            usleep(1000);
        }
    }

    m_tcpSocket->flush();

    *ret = true;
    return;
}
Пример #18
0
bool MythSocket::readStringList(QStringList &list, uint timeoutMS)
{
    list.clear();

    if (state() != Connected)
    {
        VERBOSE(VB_IMPORTANT, LOC +
                "readStringList: Error, called with unconnected socket.");
        return false;
    }

    MythTimer timer;
    timer.start();
    int elapsed = 0;

    while (waitForMore(5) < 8)
    {
        elapsed = timer.elapsed();
        if (elapsed >= (int)timeoutMS)
        {
            VERBOSE(VB_IMPORTANT, LOC + "readStringList: " +
                    QString("Error, timed out after %1 ms.").arg(timeoutMS));
            close();
            return false;
        }

        if (state() != Connected)
        {
            VERBOSE(VB_IMPORTANT, LOC +
                    "readStringList: Connection died.");
            return false;
        }

        {
            struct timeval tv;
            int maxfd;
            fd_set rfds;

            FD_ZERO(&rfds);
            FD_SET(socket(), &rfds);
            maxfd = socket();

            tv.tv_sec = 0;
            tv.tv_usec = 0;

            int rval = select(maxfd + 1, &rfds, NULL, NULL, &tv);
            if (rval)
            {
                if (bytesAvailable() == 0)
                {
                    VERBOSE(VB_IMPORTANT, LOC +
                            "readStringList: Connection died (select).");
                    return false;
                }
            }
        }
    }

    QByteArray sizestr(8 + 1, '\0');
    if (readBlock(sizestr.data(), 8) < 0)
    {
        VERBOSE(VB_GENERAL, LOC +
                QString("readStringList: Error, readBlock return error (%1)")
                .arg(errorToString()));
        close();
        return false;
    }

    QString sizes = sizestr;
    qint64 btr = sizes.trimmed().toInt();

    if (btr < 1)
    {
        int pending = bytesAvailable();
        QByteArray dump(pending + 1, 0);
        readBlock(dump.data(), pending);
        VERBOSE(VB_IMPORTANT, LOC +
                QString("Protocol error: '%1' is not a valid size "
                        "prefix. %2 bytes pending.")
                        .arg(sizestr.data()).arg(pending));
        return false;
    }

    QByteArray utf8(btr + 1, 0);

    qint64 read = 0;
    int errmsgtime = 0;
    timer.start();

    while (btr > 0)
    {
        qint64 sret = readBlock(utf8.data() + read, btr);
        if (sret > 0)
        {
            read += sret;
            btr -= sret;
            if (btr > 0)
            {
                timer.start();
            }
        }
        else if (sret < 0 && error() != MSocketDevice::NoError)
        {
            VERBOSE(VB_GENERAL, LOC +
                    QString("readStringList: Error, readBlock %1")
                    .arg(errorToString()));
            close();
            return false;
        }
        else if (!isValid())
        {
            VERBOSE(VB_IMPORTANT, LOC +
                    "readStringList: Error, socket went unconnected");
            close();
            return false;
        }
        else
        {
            elapsed = timer.elapsed();
            if (elapsed  > 10000)
            {
                if ((elapsed - errmsgtime) > 10000)
                {
                    errmsgtime = elapsed;
                    VERBOSE(VB_GENERAL, LOC +
                            QString("readStringList: Waiting for data: %1 %2")
                            .arg(read).arg(btr));
                }
            }

            if (elapsed > 100000)
            {
                VERBOSE(VB_GENERAL, LOC +
                        "Error, readStringList timeout (readBlock)");
                return false;
            }

            usleep(500);
        }
    }

    QString str = QString::fromUtf8(utf8.data());

    QByteArray payload;
    payload = payload.setNum(str.length());
    payload += "        ";
    payload.truncate(8);
    payload += str;

    if (VERBOSE_LEVEL_CHECK(VB_NETWORK))
    {
        QString msg = QString("read  <- %1 %2").arg(socket(), 2)
            .arg(payload.data());

        if (!VERBOSE_LEVEL_CHECK(VB_EXTRA) && msg.length() > 88)
        {
            msg.truncate(85);
            msg += "...";
        }
        VERBOSE(VB_NETWORK, LOC + msg);
    }

    list = str.split("[]:[]");

    m_notifyread = false;
    s_readyread_thread->WakeReadyReadThread();
    return true;
}