Exemple #1
0
/** \fn DeviceReadBuffer::WaitForUsed(uint,uint) const
 *  \param needed Number of bytes we want to read
 *  \param max_wait Number of milliseconds to wait for the needed data
 *  \return bytes available for reading
 */
uint DeviceReadBuffer::WaitForUsed(uint needed, uint max_wait) const
{
    MythTimer timer;
    timer.start();

    QMutexLocker locker(&lock);
    size_t avail = used;
    while ((needed > avail) && isRunning() &&
            !request_pause && !error && !eof &&
            (timer.elapsed() < (int)max_wait))
    {
        dataWait.wait(locker.mutex(), 10);
        avail = used;
    }
    return avail;
}
Exemple #2
0
/** \fn  SignalMonitor::WaitForLock(int)
 *  \brief Wait for a StatusSignaLock(int) of true.
 *
 *   This can be called whether or not the signal
 *   monitoring thread has been started.
 *
 *  \param timeout maximum time to wait in milliseconds.
 *  \return true if signal was acquired.
 */
bool SignalMonitor::WaitForLock(int timeout)
{
    statusLock.lock();
    if (-1 == timeout)
        timeout = signalLock.GetTimeout();
    statusLock.unlock();
    if (timeout<0)
        return false;

    MythTimer t;
    t.start();
    if (running)
    {
        while (t.elapsed()<timeout && running)
        {
            Kick();
            statusLock.lock();
            bool ok = signalLock.IsGood();
            statusLock.unlock();
            if (ok)
                return true;

            usleep(50);
        }
        if (!running)
            return WaitForLock(timeout-t.elapsed());
    }
    else
    {
        while (t.elapsed()<timeout && !running)
        {
            UpdateValues();
            statusLock.lock();
            bool ok = signalLock.IsGood();
            statusLock.unlock();
            if (ok)
                return true;

            usleep(50);
        }
        if (running)
            return WaitForLock(timeout-t.elapsed());
    }
    return false;
}
Exemple #3
0
DTC::LiveStreamInfo *HTTPLiveStream::StopStream(int id)
{
    MSqlQuery query(MSqlQuery::InitCon());
    query.prepare(
        "UPDATE livestream "
        "SET status = :STATUS "
        "WHERE id = :STREAMID; ");
    query.bindValue(":STATUS", (int)kHLSStatusStopping);
    query.bindValue(":STREAMID", id);

    if (!query.exec())
    {
        LOG(VB_GENERAL, LOG_ERR, SLOC +
            QString("Unable to remove mark stream stopped for stream %1.")
                    .arg(id));
        return NULL;
    }

    HTTPLiveStream *hls = new HTTPLiveStream(id);
    if (!hls)
        return NULL;

    MythTimer statusTimer;
    int       delay = 250000;
    statusTimer.start();

    HTTPLiveStreamStatus status = hls->GetDBStatus();
    while ((status != kHLSStatusStopped) &&
           (status != kHLSStatusCompleted) &&
           (status != kHLSStatusErrored) &&
           ((statusTimer.elapsed() / 1000) < 30))
    {
        delay = (int)(delay * 1.5);
        usleep(delay);

        status = hls->GetDBStatus();
    }

    hls->LoadFromDB();
    DTC::LiveStreamInfo *pLiveStreamInfo = hls->GetLiveStreamInfo();

    delete hls;
    return pLiveStreamInfo;
}
Exemple #4
0
void MThreadPool::startReserved(
    QRunnable *runnable, QString debugName, int waitForAvailMS)
{
    QMutexLocker locker(&m_priv->m_lock);
    if (waitForAvailMS > 0 && m_priv->m_avail_threads.empty() &&
        m_priv->m_running_threads.size() >= m_priv->m_max_thread_count)
    {
        MythTimer t;
        t.start();
        int left = waitForAvailMS - t.elapsed();
        while (left > 0 && m_priv->m_avail_threads.empty() &&
               m_priv->m_running_threads.size() >= m_priv->m_max_thread_count)
        {
            m_priv->m_wait.wait(locker.mutex(), left);
            left = waitForAvailMS - t.elapsed();
        }
    }
    TryStartInternal(runnable, debugName, true);
}
QString BufferedSocketDevice::ReadLine( int msecs )
{
    MythTimer timer;
    QString   sLine;

    if ( CanReadLine() )
        return( ReadLine() );
        
    // ----------------------------------------------------------------------
    // If the user supplied a timeout, lets loop until we can read a line 
    // or timeout.
    // ----------------------------------------------------------------------

    if ( msecs > 0)
    {
        bool bTimeout = false;

        timer.start();

        while ( !CanReadLine() && !bTimeout )
        {
#if 0
            LOG(VB_HTTP, LOG_DEBUG, "Can't Read Line... Waiting for more." );
#endif

            WaitForMore( msecs, &bTimeout );

            if ( timer.elapsed() >= msecs ) 
            {
                bTimeout = true;
                LOG(VB_HTTP, LOG_INFO, "Exceeded Total Elapsed Wait Time." );
            }
        }
            
        if (CanReadLine())
            sLine = ReadLine();
    }

    return( sLine );
}
Exemple #6
0
void PreviewGenerator::TeardownAll(void)
{
    if (!isConnected)
        return;

    const QString filename = programInfo.pathname + ".png";

    MythTimer t;
    t.start();
    for (bool done = false; !done;)
    {
        previewLock.lock();
        if (isConnected)
            emit previewThreadDone(filename, done);
        else
            done = true;
        previewLock.unlock();
        usleep(5000);
    }
    VERBOSE(VB_PLAYBACK, LOC + "previewThreadDone took "<<t.elapsed()<<"ms");
    disconnectSafe();
}
Exemple #7
0
DTC::LiveStreamInfo *HTTPLiveStream::StartStream(void)
{
    HTTPLiveStreamThread *streamThread =
        new HTTPLiveStreamThread(GetStreamID());
    MThreadPool::globalInstance()->startReserved(streamThread,
                                                 "HTTPLiveStream");
    MythTimer statusTimer;
    int       delay = 250000;
    statusTimer.start();

    HTTPLiveStreamStatus status = GetDBStatus();
    while ((status == kHLSStatusQueued) &&
           ((statusTimer.elapsed() / 1000) < 30))
    {
        delay = (int)(delay * 1.5);
        usleep(delay);

        status = GetDBStatus();
    }

    return GetLiveStreamInfo();
}
void MythSocket::ReadReal(char *data, int size, int max_wait_ms, int *ret)
{
    MythTimer t; t.start();
    while ((m_tcpSocket->state() == QAbstractSocket::ConnectedState) &&
           (m_tcpSocket->bytesAvailable() < size) &&
           (t.elapsed() < max_wait_ms))
    {
        m_tcpSocket->waitForReadyRead(max(2, max_wait_ms - t.elapsed()));
    }
    *ret = m_tcpSocket->read(data, size);

    if (t.elapsed() > 50)
    {
        LOG(VB_GENERAL, LOG_INFO,
            QString("ReadReal(?, %1, %2) -> %3 took %4 ms")
            .arg(size).arg(max_wait_ms).arg(*ret)
            .arg(t.elapsed()));
    }

    m_dataAvailable.fetchAndStoreOrdered(
        (m_tcpSocket->bytesAvailable() > 0) ? 1 : 0);
}
Exemple #9
0
void MThread::Cleanup(void)
{
    QMutexLocker locker(&s_all_threads_lock);
    QSet<MThread*> badGuys;
    QSet<MThread*>::const_iterator it;
    for (it = s_all_threads.begin(); it != s_all_threads.end(); ++it)
    {
        if ((*it)->isRunning())
        {
            badGuys.insert(*it);
            (*it)->exit(1);
        }
    }

    if (badGuys.empty())
        return;

    // logging has been stopped so we need to use iostream...
    cerr<<"Error: Not all threads were shut down properly: "<<endl;
    for (it = badGuys.begin(); it != badGuys.end(); ++it)
    {
        cerr<<"Thread "<<qPrintable((*it)->objectName())
            <<" is still running"<<endl;
    }
    cerr<<endl;

    static const int kTimeout = 5000;
    MythTimer t;
    t.start();
    for (it = badGuys.begin();
         it != badGuys.end() && t.elapsed() < kTimeout; ++it)
    {
        int left = kTimeout - t.elapsed();
        if (left > 0)
            (*it)->wait(left);
    }
}
Exemple #10
0
/** \fn PlayerContext::StartPlaying(int)
 *  \brief Starts player, must be called after StartRecorder().
 *  \param maxWait How long to wait for MythPlayer to start playing.
 *  \return true when successful, false otherwise.
 */
bool PlayerContext::StartPlaying(int maxWait)
{
    if (!player)
        return false;

    if (!player->StartPlaying())
    {
        LOG(VB_GENERAL, LOG_ERR, LOC + "StartPlaying() Failed to start player");
        // no need to call StopPlaying here as the player context will be deleted
        // later following the error
        return false;
    }
    maxWait = (maxWait <= 0) ? 20000 : maxWait;
#ifdef USING_VALGRIND
    maxWait = (1<<30);
#endif // USING_VALGRIND
    MythTimer t;
    t.start();

    while (!player->IsPlaying(50, true) && (t.elapsed() < maxWait))
        ReloadTVChain();

    if (player->IsPlaying())
    {
        LOG(VB_PLAYBACK, LOG_INFO, LOC +
            QString("StartPlaying(): took %1 ms to start player.")
                .arg(t.elapsed()));
        return true;
    }
    else
    {
        LOG(VB_GENERAL, LOG_ERR, LOC + "StartPlaying() Failed to start player");
        StopPlaying();
        return false;
    }
}
bool AudioOutputOSS::OpenDevice()
{
    numbadioctls = 0;

    MythTimer timer;
    timer.start();

    VBAUDIO(QString("Opening OSS audio device '%1'.").arg(main_device));

    while (timer.elapsed() < 2000 && audiofd == -1)
    {
        QByteArray device = main_device.toLatin1();
        audiofd = open(device.constData(), O_WRONLY);
        if (audiofd < 0 && errno != EAGAIN && errno != EINTR)
        {
            if (errno == EBUSY)
            {
                VBWARN(QString("Something is currently using: %1.")
                      .arg(main_device));
                return false;
            }
            VBERRENO(QString("Error opening audio device (%1)")
                         .arg(main_device));
        }
        if (audiofd < 0)
            usleep(50);
    }

    if (audiofd == -1)
    {
        Error(QObject::tr("Error opening audio device (%1)").arg(main_device));
        VBERRENO(QString("Error opening audio device (%1)").arg(main_device));
        return false;
    }

    if (fcntl(audiofd, F_SETFL, fcntl(audiofd, F_GETFL) & ~O_NONBLOCK) == -1)
    {
        VBERRENO(QString("Error removing the O_NONBLOCK flag from audio device FD (%1)").arg(main_device));
    }

    bool err = false;
    int  format;

    switch (output_format)
    {
        case FORMAT_U8:  format = AFMT_U8;      break;
        case FORMAT_S16: format = AFMT_S16_NE;  break;
        default:
            VBERROR(QString("Unknown sample format: %1").arg(output_format));
            close(audiofd);
            audiofd = -1;
            return false;
    }

#if defined(AFMT_AC3) && defined(SNDCTL_DSP_GETFMTS)
    if (passthru)
    {
        int format_support = 0;
        if (!ioctl(audiofd, SNDCTL_DSP_GETFMTS, &format_support) &&
            (format_support & AFMT_AC3))
        {
            format = AFMT_AC3;
        }
    }
#endif

    if (channels > 2)
    {
        if (ioctl(audiofd, SNDCTL_DSP_CHANNELS, &channels) < 0 ||
            ioctl(audiofd, SNDCTL_DSP_SPEED, &samplerate) < 0  ||
            ioctl(audiofd, SNDCTL_DSP_SETFMT, &format) < 0)
            err = true;
    }
    else
    {
        int stereo = channels - 1;
        if (ioctl(audiofd, SNDCTL_DSP_STEREO, &stereo) < 0     ||
            ioctl(audiofd, SNDCTL_DSP_SPEED, &samplerate) < 0  ||
            ioctl(audiofd, SNDCTL_DSP_SETFMT, &format) < 0)
            err = true;
    }

    if (err)
    {
        VBERRENO(QString("Unable to set audio device (%1) to %2 kHz, %3 bits, "
                         "%4 channels")
                     .arg(main_device).arg(samplerate)
                     .arg(AudioOutputSettings::FormatToBits(output_format))
                     .arg(channels));

        close(audiofd);
        audiofd = -1;
        return false;
    }

    audio_buf_info info;
    if (ioctl(audiofd, SNDCTL_DSP_GETOSPACE, &info) < 0)
        VBERRENO("Error retrieving card buffer size");
    // align by frame size
    fragment_size = info.fragsize - (info.fragsize % output_bytes_per_frame);

    soundcard_buffer_size = info.bytes;

    int caps;

    if (ioctl(audiofd, SNDCTL_DSP_GETCAPS, &caps) == 0)
    {
        if (!(caps & DSP_CAP_REALTIME))
            VBWARN("The audio device cannot report buffer state "
                   "accurately! audio/video sync will be bad, continuing...");
    }
    else
        VBERRENO("Unable to get audio card capabilities");

    // Setup volume control
    if (internal_vol)
        VolumeInit();

    // Device opened successfully
    return true;
}
Exemple #12
0
/** \fn EITScanner::RunEventLoop(void)
 *  \brief This runs the event loop for EITScanner until 'exitThread' is true.
 */
void EITScanner::RunEventLoop(void)
{
    static const uint  sz[] = { 2000, 1800, 1600, 1400, 1200, };
    static const float rt[] = { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, };

    lock.lock();
    exitThread = false;

    MythTimer t;
    uint eitCount = 0;

    while (!exitThread)
    {
        lock.unlock();
        uint list_size = eitHelper->GetListSize();

        float rate = 1.0f;
        for (uint i = 0; i < 5; i++)
        {
            if (list_size >= sz[i])
            {
                rate = rt[i];
                break;
            }
        }

        lock.lock();
        if (eitSource)
            eitSource->SetEITRate(rate);
        lock.unlock();

        if (list_size)
        {
            eitCount += eitHelper->ProcessEvents();
            t.start();
        }

        // If there have been any new events and we haven't
        // seen any in a while, tell scheduler to run.
        if (eitCount && (t.elapsed() > 60 * 1000))
        {
            VERBOSE(VB_EIT, LOC_ID + "Added "<<eitCount<<" EIT Events");
            eitCount = 0;
            RescheduleRecordings();
        }

        if (activeScan && (QDateTime::currentDateTime() > activeScanNextTrig))
        {
            // if there have been any new events, tell scheduler to run.
            if (eitCount)
            {
                VERBOSE(VB_EIT, LOC_ID + "Added "<<eitCount<<" EIT Events");
                eitCount = 0;
                RescheduleRecordings();
            }

            if (activeScanNextChan == activeScanChannels.end())
                activeScanNextChan = activeScanChannels.begin();

            if (!(*activeScanNextChan).isEmpty())
            {
                eitHelper->WriteEITCache();
                rec->SetChannel(*activeScanNextChan, TVRec::kFlagEITScan);
                VERBOSE(VB_EIT, LOC_ID +
                        QString("Now looking for EIT data on "
                                "multiplex of channel %1")
                        .arg(*activeScanNextChan));
            }

            activeScanNextTrig = QDateTime::currentDateTime()
                .addSecs(activeScanTrigTime);
            activeScanNextChan++;

            // 24 hours ago
            eitHelper->PruneEITCache(activeScanNextTrig.toTime_t() - 86400);
        }

        lock.lock();
        if (!exitThread)
            exitThreadCond.wait(&lock, 400); // sleep up to 400 ms.
    }
    lock.unlock();
}
Exemple #13
0
int RemoteFile::Read(void *data, int size)
{
    int recv = 0;
    int sent = 0;
    bool error = false;
    bool response = false;

    QMutexLocker locker(&lock);
    if (!sock)
    {
        LOG(VB_NETWORK, LOG_ERR, "RemoteFile::Read(): Called with no socket");
        return -1;
    }

    if (!sock->IsConnected() || !controlSock->IsConnected())
        return -1;

    if (sock->IsDataAvailable())
    {
        LOG(VB_NETWORK, LOG_ERR,
            "RemoteFile::Read(): Read socket not empty to start!");
        sock->Reset();
    }

    while (controlSock->IsDataAvailable())
    {
        LOG(VB_NETWORK, LOG_ERR,
            "RemoteFile::Read(): Control socket not empty to start!");
        controlSock->Reset();
    }

    QStringList strlist( QString(query).arg(recordernum) );
    strlist << "REQUEST_BLOCK";
    strlist << QString::number(size);
    bool ok = controlSock->WriteStringList(strlist);
    if (!ok)
    {
        LOG(VB_NETWORK, LOG_ERR, "RemoteFile::Read(): Block request failed");
        return -1;
    }

    sent = size;

    int waitms = 10;
    MythTimer mtimer;
    mtimer.start();

    while (recv < sent && !error && mtimer.elapsed() < 10000)
    {
        int ret = sock->Read(((char *)data) + recv, sent - recv, waitms);

        if (ret > 0)
            recv += ret;
        else if (ret < 0)
            error = true;

        waitms += (waitms < 200) ? 20 : 0;

        if (controlSock->IsDataAvailable() &&
                controlSock->ReadStringList(strlist, MythSocket::kShortTimeout) &&
                !strlist.empty())
        {
            sent = strlist[0].toInt(); // -1 on backend error
            response = true;
        }
    }

    if (!error && !response)
    {
        if (controlSock->ReadStringList(strlist, MythSocket::kShortTimeout) &&
                !strlist.empty())
        {
            sent = strlist[0].toInt(); // -1 on backend error
        }
        else
        {
            LOG(VB_GENERAL, LOG_ERR,
                "RemoteFile::Read(): No response from control socket.");
            sent = -1;
        }
    }

    LOG(VB_NETWORK, LOG_DEBUG,
        QString("Read(): reqd=%1, rcvd=%2, rept=%3, error=%4")
        .arg(size).arg(recv).arg(sent).arg(error));

    if (sent < 0)
        return sent;

    if (error || sent != recv)
        recv = -1;

    return recv;
}
Exemple #14
0
bool AudioOutputOSS::OpenDevice()
{
    numbadioctls = 0;

    MythTimer timer;
    timer.start();

    VERBOSE(VB_GENERAL, QString("Opening OSS audio device '%1'.")
            .arg(audio_main_device));
    
    while (timer.elapsed() < 2000 && audiofd == -1)
    {
        audiofd = open(audio_main_device.ascii(), O_WRONLY | O_NONBLOCK);
        if (audiofd < 0 && errno != EAGAIN && errno != EINTR)
        {
            if (errno == EBUSY)
            {
                Error(QString("WARNING: something is currently"
                              " using: %1, retrying.").arg(audio_main_device));
                return false;
            }
            VERBOSE(VB_IMPORTANT, QString("Error opening audio device (%1), the"
                    " error was: %2").arg(audio_main_device).arg(strerror(errno)));
            perror(audio_main_device.ascii());
        }
        if (audiofd < 0)
            usleep(50);
    }

    if (audiofd == -1)
    {
        Error(QString("Error opening audio device (%1), the error was: %2")
              .arg(audio_main_device).arg(strerror(errno)));
        return false;
    }

    fcntl(audiofd, F_SETFL, fcntl(audiofd, F_GETFL) & ~O_NONBLOCK);

    SetFragSize();

    bool err = false;
    int  format;

    switch (audio_bits)
    {
        case 8:
            format = AFMT_S8;
            break;
        case 16:
#ifdef WORDS_BIGENDIAN
            format = AFMT_S16_BE;
#else
            format = AFMT_S16_LE;
#endif
            break;
        default: Error(QString("AudioOutputOSS() - Illegal bitsize of %1")
                       .arg(audio_bits));
    }

#if defined(AFMT_AC3) && defined(SNDCTL_DSP_GETFMTS)
    if (audio_passthru)
    {
        int format_support;
        if (!ioctl(audiofd, SNDCTL_DSP_GETFMTS, &format_support) &&
            (format_support & AFMT_AC3))
        {
            format = AFMT_AC3;
        }
    }
#endif

    if (audio_channels > 2)
    {
        if (ioctl(audiofd, SNDCTL_DSP_SAMPLESIZE, &audio_bits) < 0 ||
            ioctl(audiofd, SNDCTL_DSP_CHANNELS, &audio_channels) < 0 ||
            ioctl(audiofd, SNDCTL_DSP_SPEED, &audio_samplerate) < 0 ||
            ioctl(audiofd, SNDCTL_DSP_SETFMT, &format) < 0)
            err = true;
    }
    else
    {
        int stereo = audio_channels - 1;
        if (ioctl(audiofd, SNDCTL_DSP_SAMPLESIZE, &audio_bits) < 0 ||
            ioctl(audiofd, SNDCTL_DSP_STEREO, &stereo) < 0 ||
            ioctl(audiofd, SNDCTL_DSP_SPEED, &audio_samplerate) < 0 ||
            ioctl(audiofd, SNDCTL_DSP_SETFMT, &format) < 0)
            err = true;
    }

    if (err)
    {
        Error(QString("Unable to set audio device (%1) to %2 kHz / %3 bits"
                      " / %4 channels").arg(audio_main_device).arg(audio_samplerate)
                      .arg(audio_bits).arg(audio_channels));
        close(audiofd);
        audiofd = -1;
        return false;
    }

    audio_buf_info info;
    ioctl(audiofd, SNDCTL_DSP_GETOSPACE, &info);
    fragment_size = info.fragsize;

    audio_buffer_unused = info.bytes - (fragment_size * 4);
    soundcard_buffer_size = info.bytes;

    int caps;
    
    if (ioctl(audiofd, SNDCTL_DSP_GETCAPS, &caps) == 0)
    {
        if (!(caps & DSP_CAP_REALTIME))
        {
            VERBOSE(VB_IMPORTANT, "The audio device cannot report buffer state"
                    " accurately! audio/video sync will be bad, continuing...");
        }
    } else {
        VERBOSE(VB_IMPORTANT, QString("Unable to get audio card capabilities,"
                " the error was: %1").arg(strerror(errno)));
    }

    // Setup volume control
    if (internal_vol)
        VolumeInit();

    // Device opened successfully
    return true;
}
Exemple #15
0
void IconData::UpdateSourceIcons(uint sourceid)
{
    VERBOSE(VB_GENERAL, LOC +
            QString("Updating icons for sourceid: %1").arg(sourceid));

    QString fileprefix = SetupIconCacheDirectory();

    MSqlQuery query(MSqlQuery::InitCon());
    query.prepare(
        "SELECT ch.chanid, nim.url "
        "FROM (channel ch, callsignnetworkmap csm) "
        "RIGHT JOIN networkiconmap nim ON csm.network = nim.network "
        "WHERE ch.callsign = csm.callsign AND "
        "      (icon = :NOICON OR icon = '') AND "
        "      ch.sourceid = :SOURCEID");
    query.bindValue(":SOURCEID", sourceid);
    query.bindValue(":NOICON", "none");

    if (!query.exec())
    {
        MythDB::DBError("Looking for icons to fetch", query);
        return;
    }

    unsigned int count = 0;
    while (query.next())
    {
        count++;

        QString icon_url = expandURLString(query.value(1).toString());
        QFileInfo qfi(icon_url);
        QFile localfile(fileprefix + "/" + qfi.fileName());

        if (!localfile.exists() || 0 == localfile.size())
        {
            VERBOSE(VB_GENERAL, LOC +
                    QString("Attempting to fetch icon at '%1'")
                    .arg(icon_url));

            FI fi;
            fi.filename = localfile.fileName();
            fi.chanid = query.value(0).toUInt();

            bool add_request = false;
            {
                QMutexLocker locker(&m_u2fl_lock);
                add_request = m_u2fl[icon_url].empty();
                m_u2fl[icon_url].push_back(fi);
            }

            if (add_request)
                MythHttpPool::GetSingleton()->AddUrlRequest(icon_url, this);

            // HACK -- begin
            // This hack is needed because we don't enter the event loop
            // before running this code via qApp->exec()
            qApp->processEvents();
            // HACK -- end
        }
    }

    MythTimer tm; tm.start();
    while (true)
    {
        // HACK -- begin
        // This hack is needed because we don't enter the event loop
        // before running this code via qApp->exec()
        qApp->processEvents();
        // HACK -- end

        QMutexLocker locker(&m_u2fl_lock);
        if (m_u2fl.empty())
            break;

        if ((uint)tm.elapsed() > (count * 500) + 2000)
        {
            VERBOSE(VB_IMPORTANT, LOC_WARN +
                    "Timed out waiting for some icons to download, "
                    "you may wish to try again later.");
            break;
        }
    }
}
/**
 * Get the default backend from config.xml, use UPnP to find it.
 *
 * Sets a string if there any connection problems
 */
bool MythContextPrivate::DefaultUPnP(QString &error)
{
    QString            loc = "DefaultUPnP() - ";
    QString            PIN = m_pConfig->GetValue(kDefaultPIN, "");
    QString            USN = m_pConfig->GetValue(kDefaultUSN, "");

    if (USN.isEmpty())
    {
        LOG(VB_UPNP, LOG_INFO, loc + "No default UPnP backend");
        return false;
    }

    LOG(VB_UPNP, LOG_INFO, loc + "config.xml has default " +
             QString("PIN '%1' and host USN: %2") .arg(PIN).arg(USN));

    // ----------------------------------------------------------------------

    int timeout_ms = 2000;
    LOG(VB_GENERAL, LOG_INFO, QString("UPNP Search up to %1 secs")
        .arg(timeout_ms / 1000));
    SSDP::Instance()->PerformSearch(gBackendURI, timeout_ms / 1000);

    // ----------------------------------------------------------------------
    // We need to give the server time to respond...
    // ----------------------------------------------------------------------

    DeviceLocation *pDevLoc = NULL;
    MythTimer totalTime; totalTime.start();
    MythTimer searchTime; searchTime.start();
    while (totalTime.elapsed() < timeout_ms)
    {
        pDevLoc = SSDP::Instance()->Find( gBackendURI, USN );

        if (pDevLoc)
            break;

        usleep(25000);

        int ttl = timeout_ms - totalTime.elapsed();
        if ((searchTime.elapsed() > 249) && (ttl > 1000))
        {
            LOG(VB_GENERAL, LOG_INFO, QString("UPNP Search up to %1 secs")
                .arg(ttl / 1000));
            SSDP::Instance()->PerformSearch(gBackendURI, ttl / 1000);
            searchTime.start();
        }
    }

    // ----------------------------------------------------------------------

    if (!pDevLoc)
    {
        error = "Cannot find default UPnP backend";
        return false;
    }

    if (UPnPconnect(pDevLoc, PIN))
    {
        pDevLoc->DecrRef();
        return true;
    }

    pDevLoc->DecrRef();

    error = "Cannot connect to default backend via UPnP. Wrong saved PIN?";
    return false;
}
Exemple #17
0
bool FileRingBuffer::OpenFile(const QString &lfilename, uint retry_ms)
{
    LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("OpenFile(%1, %2 ms)")
            .arg(lfilename).arg(retry_ms));

    rwlock.lockForWrite();

    filename = lfilename;

    if (remotefile)
    {
        delete remotefile;
        remotefile = NULL;
    }

    if (fd2 >= 0)
    {
        close(fd2);
        fd2 = -1;
    }

    bool is_local = 
        (filename.left(4) != "/dev") &&
        ((filename.left(1) == "/") || QFile::exists(filename));

    if (is_local)
    {
        char buf[kReadTestSize];
        int lasterror = 0;

        MythTimer openTimer;
        openTimer.start();

        uint openAttempts = 0;
        do
        {
            openAttempts++;
            lasterror = 0;

            fd2 = open(filename.toLocal8Bit().constData(),
                       O_RDONLY|O_LARGEFILE|O_STREAMING|O_BINARY);

            if (fd2 < 0)
            {
                if (!check_permissions(filename))
                {
                    lasterror = 3;
                    break;
                }

                lasterror = 1;
                usleep(10 * 1000);
            }
            else
            {
                int ret = read(fd2, buf, kReadTestSize);
                if (ret != (int)kReadTestSize)
                {
                    lasterror = 2;
                    close(fd2);
                    fd2 = -1;
                    if (oldfile)
                        break; // if it's an old file it won't grow..
                    usleep(10 * 1000);
                }
                else
                {
                    if (0 == lseek(fd2, 0, SEEK_SET))
                    {
                        posix_fadvise(fd2, 0, 0,        POSIX_FADV_SEQUENTIAL);
                        posix_fadvise(fd2, 0, 128*1024, POSIX_FADV_WILLNEED);
                        lasterror = 0;
                        break;
                    }
                    lasterror = 4;
                    close(fd2);
                    fd2 = -1;
                }
            }
        }
        while ((uint)openTimer.elapsed() < retry_ms);

        switch (lasterror)
        {
            case 0:
            {
                QFileInfo fi(filename);
                oldfile = fi.lastModified()
                    .secsTo(QDateTime::currentDateTime()) > 60;
                QString extension = fi.completeSuffix().toLower();
                if (is_subtitle_possible(extension))
                    subtitlefilename = local_sub_filename(fi);
                break;
            }
            case 1:
                LOG(VB_GENERAL, LOG_ERR, LOC +
                        QString("OpenFile(): Could not open."));
                break;
            case 2:
                LOG(VB_GENERAL, LOG_ERR, LOC +
                        QString("OpenFile(): File too small (%1B).")
                        .arg(QFileInfo(filename).size()));
                break;
            case 3:
                LOG(VB_GENERAL, LOG_ERR, LOC +
                        "OpenFile(): Improper permissions.");
                break;
            case 4:
                LOG(VB_GENERAL, LOG_ERR, LOC +
                        "OpenFile(): Cannot seek in file.");
                break;
            default:
                break;
        }
        LOG(VB_FILE, LOG_INFO, 
            LOC + QString("OpenFile() made %1 attempts in %2 ms")
                .arg(openAttempts).arg(openTimer.elapsed()));

    }
    else
    {
        QString tmpSubName = filename;
        QString dirName  = ".";

        int dirPos = filename.lastIndexOf(QChar('/'));
        if (dirPos > 0)
        {
            tmpSubName = filename.mid(dirPos + 1);
            dirName = filename.left(dirPos);
        }

        QString baseName  = tmpSubName;
        QString extension = tmpSubName;
        QStringList auxFiles;

        int suffixPos = tmpSubName.lastIndexOf(QChar('.'));
        if (suffixPos > 0)
        {
            baseName = tmpSubName.left(suffixPos);
            extension = tmpSubName.right(suffixPos-1);
            if (is_subtitle_possible(extension))
            {
                QMutexLocker locker(&subExtLock);
                QStringList::const_iterator eit = subExt.begin();
                for (; eit != subExt.end(); ++eit)
                    auxFiles += baseName + *eit;
            }
        }

        remotefile = new RemoteFile(filename, false, true,
                                    retry_ms, &auxFiles);
        if (!remotefile->isOpen())
        {
            LOG(VB_GENERAL, LOG_ERR, LOC +
                    QString("RingBuffer::RingBuffer(): Failed to open remote "
                            "file (%1)").arg(filename));
            delete remotefile;
            remotefile = NULL;
        }
        else
        {
            QStringList aux = remotefile->GetAuxiliaryFiles();
            if (aux.size())
                subtitlefilename = dirName + "/" + aux[0];
        }
    }

    setswitchtonext = false;
    ateof = false;
    commserror = false;
    numfailures = 0;

    rawbitrate = 8000;
    CalcReadAheadThresh();

    bool ok = fd2 >= 0 || remotefile;

    rwlock.unlock();

    return ok;
}
Exemple #18
0
void MpegRecorder::run(void)
{
    if (!Open())
    {
        if (_error.isEmpty())
            _error = "Failed to open V4L device";
        return;
    }

    bool has_select = true;

#if defined(__FreeBSD__)
    // HACK. FreeBSD PVR150/500 driver doesn't currently support select()
    has_select = false;
#endif

    if (driver == "hdpvr")
    {
        int progNum = 1;
        MPEGStreamData *sd = new MPEGStreamData
                             (progNum, tvrec ? tvrec->GetCaptureCardNum() : -1,
                              true);
        sd->SetRecordingType(_recording_type);
        SetStreamData(sd);

        _stream_data->AddAVListener(this);
        _stream_data->AddWritingListener(this);

        // Make sure the first things in the file are a PAT & PMT
        HandleSingleProgramPAT(_stream_data->PATSingleProgram(), true);
        HandleSingleProgramPMT(_stream_data->PMTSingleProgram(), true);
        _wait_for_keyframe_option = true;
    }

    {
        QMutexLocker locker(&pauseLock);
        request_recording = true;
        request_helper = true;
        recording = true;
        recordingWait.wakeAll();
    }

    unsigned char *buffer = new unsigned char[bufferSize + 1];
    int len;
    int remainder = 0;

    bool      good_data = false;
    bool      gap = false;
    QDateTime gap_start;

    MythTimer elapsedTimer;
    float elapsed;
    long long bytesRead = 0;
    int dummyBPS = 0;  // Bytes per second, but env var is BITS PER SECOND

    if (getenv("DUMMYBPS"))
    {
        dummyBPS = atoi(getenv("DUMMYBPS")) / 8;
        LOG(VB_GENERAL, LOG_INFO,
            LOC + QString("Throttling dummy recorder to %1 bits per second")
                .arg(dummyBPS * 8));
    }

    struct timeval tv;
    fd_set rdset;

    if (deviceIsMpegFile)
        elapsedTimer.start();
    else if (_device_read_buffer)
    {
        LOG(VB_RECORD, LOG_INFO, LOC + "Initial startup of recorder");
        StartEncoding();
    }

    QByteArray vdevice = videodevice.toLatin1();
    while (IsRecordingRequested() && !IsErrored())
    {
        if (PauseAndWait(100))
            continue;

        if (deviceIsMpegFile)
        {
            if (dummyBPS && bytesRead)
            {
                elapsed = (elapsedTimer.elapsed() / 1000.0) + 1;
                while ((bytesRead / elapsed) > dummyBPS)
                {
                    usleep(50000);
                    elapsed = (elapsedTimer.elapsed() / 1000.0) + 1;
                }
            }
            else if (GetFramesWritten())
            {
                elapsed = (elapsedTimer.elapsed() / 1000.0) + 1;
                while ((GetFramesWritten() / elapsed) > 30)
                {
                    usleep(50000);
                    elapsed = (elapsedTimer.elapsed() / 1000.0) + 1;
                }
            }
        }

        if (_device_read_buffer)
        {
            len = _device_read_buffer->Read
                  (&(buffer[remainder]), bufferSize - remainder);

            // Check for DRB errors
            if (_device_read_buffer->IsErrored())
            {
                LOG(VB_GENERAL, LOG_ERR, LOC + "Device error detected");

                if (good_data)
                {
                    if (gap)
                    {
                        /* Already processing a gap, which means
                         * restarting the encoding didn't work! */
                        SetRecordingStatus(rsFailing, __FILE__, __LINE__);
                    }
                    else
                        gap = true;
                }

                RestartEncoding();
            }
            else if (_device_read_buffer->IsEOF() &&
                     IsRecordingRequested())
            {
                LOG(VB_GENERAL, LOG_ERR, LOC + "Device EOF detected");
                _error = "Device EOF detected";
            }
            else
            {
                // If we have seen good data, but now have a gap, note it
                if (good_data)
                {
                    if (gap)
                    {
                        QMutexLocker locker(&statisticsLock);
                        QDateTime gap_end(MythDate::current());

                        recordingGaps.push_back(RecordingGap
                                                (gap_start, gap_end));
                        LOG(VB_RECORD, LOG_DEBUG,
                            LOC + QString("Inserted gap %1 dur %2")
                            .arg(recordingGaps.back().toString())
                            .arg(gap_start.secsTo(gap_end)));
                        gap = false;
                    }
                    else
                        gap_start = MythDate::current();
                }
                else
                    good_data = true;
            }
        }
        else
        {
            if (has_select)
            {
                tv.tv_sec = 5;
                tv.tv_usec = 0;
                FD_ZERO(&rdset);
                FD_SET(readfd, &rdset);

                switch (select(readfd + 1, &rdset, NULL, NULL, &tv))
                {
                    case -1:
                        if (errno == EINTR)
                            continue;

                        LOG(VB_GENERAL, LOG_ERR, LOC + "Select error" + ENO);
                        continue;

                    case 0:
                        LOG(VB_GENERAL, LOG_ERR, LOC + "select timeout - "
                                "driver has stopped responding");

                        if (close(readfd) != 0)
                        {
                            LOG(VB_GENERAL, LOG_ERR, LOC + "Close error" + ENO);
                        }

                        // Force card to be reopened on next iteration..
                        readfd = -1;
                        continue;

                    default:
                        break;
                }
            }

            len = read(readfd, &(buffer[remainder]), bufferSize - remainder);

            if (len < 0 && !has_select)
            {
                QMutexLocker locker(&pauseLock);
                if (request_recording && !request_pause)
                    unpauseWait.wait(&pauseLock, 25);
                continue;
            }

            if ((len == 0) && (deviceIsMpegFile))
            {
                close(readfd);
                readfd = open(vdevice.constData(), O_RDONLY);

                if (readfd >= 0)
                {
                    len = read(readfd,
                               &(buffer[remainder]), bufferSize - remainder);
                }

                if (len <= 0)
                {
                    _error = "Failed to read from video file";
                    continue;
                }
            }
            else if (len < 0 && errno != EAGAIN)
            {
                LOG(VB_GENERAL, LOG_ERR, LOC + QString("error reading from: %1")
                        .arg(videodevice) + ENO);
                continue;
            }
        }

        if (len > 0)
        {
            bytesRead += len;
            len += remainder;

            if (driver == "hdpvr")
            {
                remainder = _stream_data->ProcessData(buffer, len);
                int start_remain = len - remainder;
                if (remainder && (start_remain >= remainder))
                    memcpy(buffer, buffer+start_remain, remainder);
                else if (remainder)
                    memmove(buffer, buffer+start_remain, remainder);
            }
            else
            {
                FindPSKeyFrames(buffer, len);
            }
        }
    }

    LOG(VB_RECORD, LOG_INFO, LOC + "run finishing up");

    StopEncoding();

    {
        QMutexLocker locker(&pauseLock);
        request_helper = false;
    }

    if (vbi_thread)
    {
        vbi_thread->wait();
        delete vbi_thread;
        vbi_thread = NULL;
        CloseVBIDevice();
    }

    FinishRecording();

    delete[] buffer;

    if (driver == "hdpvr")
    {
        _stream_data->RemoveWritingListener(this);
        _stream_data->RemoveAVListener(this);
        SetStreamData(NULL);
    }

    QMutexLocker locker(&pauseLock);
    request_recording = false;
    recording = false;
    recordingWait.wakeAll();
}
/**
 * If there is only a single UPnP backend, use it.
 *
 * This does <i>not</i> prompt for PIN entry. If the backend requires one,
 * it will fail, and the caller needs to put up a UI to ask for one.
 */
int MythContextPrivate::UPnPautoconf(const int milliSeconds)
{
    LOG(VB_GENERAL, LOG_INFO, QString("UPNP Search %1 secs")
        .arg(milliSeconds / 1000));

    SSDP::Instance()->PerformSearch(gBackendURI, milliSeconds / 1000);

    // Search for a total of 'milliSeconds' ms, sending new search packet
    // about every 250 ms until less than one second remains.
    MythTimer totalTime; totalTime.start();
    MythTimer searchTime; searchTime.start();
    while (totalTime.elapsed() < milliSeconds)
    {
        usleep(25000);
        int ttl = milliSeconds - totalTime.elapsed();
        if ((searchTime.elapsed() > 249) && (ttl > 1000))
        {
            LOG(VB_GENERAL, LOG_INFO, QString("UPNP Search %1 secs")
                .arg(ttl / 1000));
            SSDP::Instance()->PerformSearch(gBackendURI, ttl / 1000);
            searchTime.start();
        }
    }

    SSDPCacheEntries *backends = SSDP::Instance()->Find(gBackendURI);

    if (!backends)
    {
        LOG(VB_GENERAL, LOG_INFO, "No UPnP backends found");
        return 0;
    }

    int count = backends->Count();
    if (count)
    {
        LOG(VB_GENERAL, LOG_INFO,
            QString("Found %1 UPnP backends").arg(count));
    }
    else
    {
        LOG(VB_GENERAL, LOG_ERR,
            "No UPnP backends found, but SSDP::Find() not NULL");
    }

    if (count != 1)
    {
        backends->DecrRef();
        return count;
    }

    // Get this backend's location:
    DeviceLocation *BE = backends->GetFirst();
    backends->DecrRef();
    backends = NULL;

    // We don't actually know the backend's access PIN, so this will
    // only work for ones that have PIN access disabled (i.e. 0000)
    int ret = (UPnPconnect(BE, QString::null)) ? 1 : -1;

    BE->DecrRef();

    return ret;
}
Exemple #20
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;
}
Exemple #21
0
int RemoteFile::Read(void *data, int size)
{
    int recv = 0;
    int sent = 0;
    bool error = false;
    bool response = false;

    QMutexLocker locker(&lock);

    if (isLocal())
    {
        if (writemode)
        {
            LOG(VB_FILE, LOG_ERR, "RemoteFile:Read() called in writing mode");
            return -1;
        }
        if (isOpen())
        {
            return ::read(localFile, data, size);
        }
        LOG(VB_FILE, LOG_ERR, "RemoteFile:Read() called when local file not opened");
        return -1;
    }

    if (!CheckConnection())
    {
        LOG(VB_NETWORK, LOG_ERR, "RemoteFile::Read(): Couldn't connect");
        return -1;
    }

    if (sock->IsDataAvailable())
    {
        LOG(VB_NETWORK, LOG_ERR,
                "RemoteFile::Read(): Read socket not empty to start!");
        sock->Reset();
    }

    while (controlSock->IsDataAvailable())
    {
        LOG(VB_NETWORK, LOG_WARNING,
                "RemoteFile::Read(): Control socket not empty to start!");
        controlSock->Reset();
    }

    QStringList strlist( QString(query).arg(recordernum) );
    strlist << "REQUEST_BLOCK";
    strlist << QString::number(size);
    bool ok = controlSock->WriteStringList(strlist);
    if (!ok)
    {
        LOG(VB_NETWORK, LOG_ERR, "RemoteFile::Read(): Block request failed");
        return -1;
    }

    sent = size;

    int waitms = 30;
    MythTimer mtimer;
    mtimer.start();

    while (recv < sent && !error && mtimer.elapsed() < 10000)
    {
        int ret = sock->Read(((char *)data) + recv, sent - recv, waitms);

        if (ret > 0)
            recv += ret;
        else if (ret < 0)
            error = true;

        waitms += (waitms < 200) ? 20 : 0;

        if (controlSock->IsDataAvailable() &&
            controlSock->ReadStringList(strlist, MythSocket::kShortTimeout) &&
            !strlist.isEmpty())
        {
            sent = strlist[0].toInt(); // -1 on backend error
            response = true;
            if (ret < sent)
            {
                // We have received less than what the server sent, retry immediately
                ret = sock->Read(((char *)data) + recv, sent - recv, waitms);
                if (ret > 0)
                    recv += ret;
                else if (ret < 0)
                    error = true;
            }
        }
    }

    if (!error && !response)
    {
        // Wait up to 1.5s for the backend to send the size
        // MythSocket::ReadString will drop the connection
        if (controlSock->ReadStringList(strlist, 1500) &&
            !strlist.isEmpty())
        {
            sent = strlist[0].toInt(); // -1 on backend error
        }
        else
        {
            LOG(VB_GENERAL, LOG_ERR,
                   "RemoteFile::Read(): No response from control socket.");
            // If no data was received from control socket, and we got what we asked for
            // assume everything is okay
            if (recv == size)
            {
                sent = recv;
            }
            else
            {
                sent = -1;
            }
            // The TCP socket is dropped if there's a timeout, so we reconnect
            if (!Resume())
            {
                sent = -1;
            }
        }
    }

    LOG(VB_NETWORK, LOG_DEBUG,
        QString("Read(): reqd=%1, rcvd=%2, rept=%3, error=%4")
            .arg(size).arg(recv).arg(sent).arg(error));

    if (sent < 0)
        return sent;

    if (error || sent != recv)
    {
        recv = -1;
    }
    else
    {
        lastposition += recv;
    }

    return recv;
}
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;
}
Exemple #23
0
int RemoteFile::Read(void *data, int size)
{
    int recv = 0;
    int sent = 0;
    bool error = false;
    bool response = false;

    QMutexLocker locker(&lock);
    if (!sock)
    {
        LOG(VB_NETWORK, LOG_ERR, "RemoteFile::Read(): Called with no socket");
        return -1;
    }

    if (!sock->isOpen() || sock->error())
        return -1;

    if (!controlSock->isOpen() || controlSock->error())
        return -1;

    if (sock->bytesAvailable() > 0)
    {
        LOG(VB_NETWORK, LOG_ERR,
                "RemoteFile::Read(): Read socket not empty to start!");
        while (sock->waitForMore(5) > 0)
        {
            int avail = sock->bytesAvailable();
            char *trash = new char[avail + 1];
            sock->readBlock(trash, avail);
            delete [] trash;
        }
    }

    if (controlSock->bytesAvailable() > 0)
    {
        LOG(VB_NETWORK, LOG_ERR,
                "RemoteFile::Read(): Control socket not empty to start!");
        QStringList tempstrlist;
        controlSock->readStringList(tempstrlist);
    }

    QStringList strlist( QString(query).arg(recordernum) );
    strlist << "REQUEST_BLOCK";
    strlist << QString::number(size);
    controlSock->writeStringList(strlist);

    sent = size;

    int waitms = 10;
    MythTimer mtimer;
    mtimer.start();

    while (recv < sent && !error && mtimer.elapsed() < 10000)
    {
        while (recv < sent && sock->waitForMore(waitms) > 0)
        {
            int ret = sock->readBlock(((char *)data) + recv, sent - recv);
            if (ret > 0)
            {
                recv += ret;
            }
            else if (sock->error() != MythSocket::NoError)
            {
                LOG(VB_GENERAL, LOG_ERR, "RemoteFile::Read(): socket error");
                error = true;
                break;
            }

            if (waitms < 200)
                waitms += 20;
        }

        if (controlSock->bytesAvailable() > 0)
        {
            controlSock->readStringList(strlist, true);
            sent = strlist[0].toInt(); // -1 on backend error
            response = true;
        }
    }

    if (!error && !response)
    {
        if (controlSock->readStringList(strlist, true))
        {
            sent = strlist[0].toInt(); // -1 on backend error
        }
        else
        {
            LOG(VB_GENERAL, LOG_ERR,
                   "RemoteFile::Read(): No response from control socket.");
            sent = -1;
        }
    }

    LOG(VB_NETWORK, LOG_DEBUG,
        QString("Read(): reqd=%1, rcvd=%2, rept=%3, error=%4")
            .arg(size).arg(recv).arg(sent).arg(error));

    if (sent < 0)
        return sent;

    if (error || sent != recv)
        recv = -1;

    return recv;
}
Exemple #24
0
/**
 *  \brief This runs the event loop for EITScanner until 'exitThread' is true.
 */
void EITScanner::run(void)
{
    static const uint  sz[] = { 2000, 1800, 1600, 1400, 1200, };
    static const float rt[] = { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, };

    lock.lock();

    MythTimer t;
    uint eitCount = 0;

    while (!exitThread)
    {
        lock.unlock();
        uint list_size = eitHelper->GetListSize();

        float rate = 1.0f;
        for (uint i = 0; i < 5; i++)
        {
            if (list_size >= sz[i])
            {
                rate = rt[i];
                break;
            }
        }

        lock.lock();
        if (eitSource)
            eitSource->SetEITRate(rate);
        lock.unlock();

        if (list_size)
        {
            eitCount += eitHelper->ProcessEvents();
            t.start();
        }

        // Tell the scheduler to run if
        // we are in passive scan
        // and there have been updated events since the last scheduler run
        // but not in the last 60 seconds
        if (!activeScan && eitCount && (t.elapsed() > 60 * 1000))
        {
            LOG(VB_EIT, LOG_INFO,
                LOC_ID + QString("Added %1 EIT Events").arg(eitCount));
            eitCount = 0;
            RescheduleRecordings();
        }

        // Is it time to move to the next transport in active scan?
        if (activeScan && (MythDate::current() > activeScanNextTrig))
        {
            // if there have been any new events, tell scheduler to run.
            if (eitCount)
            {
                LOG(VB_EIT, LOG_INFO,
                    LOC_ID + QString("Added %1 EIT Events").arg(eitCount));
                eitCount = 0;
                RescheduleRecordings();
            }

            if (activeScanNextChan == activeScanChannels.end())
                activeScanNextChan = activeScanChannels.begin();

            if (!(*activeScanNextChan).isEmpty())
            {
                eitHelper->WriteEITCache();
                if (rec->QueueEITChannelChange(*activeScanNextChan))
                {
                    eitHelper->SetChannelID(ChannelUtil::GetChanID(
                        rec->GetSourceID(), *activeScanNextChan));
                    LOG(VB_EIT, LOG_INFO,
                        LOC_ID + QString("Now looking for EIT data on "
                                         "multiplex of channel %1")
                        .arg(*activeScanNextChan));
                }
            }

            activeScanNextTrig = MythDate::current()
                .addSecs(activeScanTrigTime);
            ++activeScanNextChan;

            // 24 hours ago
            eitHelper->PruneEITCache(activeScanNextTrig.toTime_t() - 86400);
        }

        lock.lock();
        if ((activeScan || activeScanStopped) && !exitThread)
            exitThreadCond.wait(&lock, 400); // sleep up to 400 ms.

        if (!activeScan && !activeScanStopped)
        {
            activeScanStopped = true;
            activeScanCond.wakeAll();
        }
    }

    if (eitCount) /* some events have been handled since the last schedule request */
    {
        eitCount = 0;
        RescheduleRecordings();
    }

    activeScanStopped = true;
    activeScanCond.wakeAll();
    lock.unlock();
}
Exemple #25
0
bool DeviceReadBuffer::Poll(void) const
{
#ifdef USING_MINGW
# ifdef _MSC_VER
#  pragma message( "mingw DeviceReadBuffer::Poll" )
# else
#  warning mingw DeviceReadBuffer::Poll
# endif
    VERBOSE(VB_IMPORTANT, LOC_ERR +
            "mingw DeviceReadBuffer::Poll is not implemented");
    return false;
#else
    bool retval = true;
    MythTimer timer;
    timer.start();

    while (true)
    {
        struct pollfd polls;
        polls.fd      = _stream_fd;
        polls.events  = POLLIN;
        polls.revents = 0;

        int ret = poll(&polls, 1 /*number of polls*/, 10 /*msec*/);

        if (polls.revents & (POLLHUP | POLLNVAL))
        {
            VERBOSE(VB_IMPORTANT, LOC + "poll error");
            error = true;
            return true;
        }

        if (!run || !IsOpen() || IsPauseRequested())
        {
            retval = false;
            break; // are we supposed to pause, stop, etc.
        }

        if (ret > 0)
            break; // we have data to read :)
        else if (ret < 0)
        {
            if ((EOVERFLOW == errno))
                break; // we have an error to handle

            if ((EAGAIN == errno) || (EINTR  == errno))
                continue; // errors that tell you to try again

            usleep(2500 /*2.5 ms*/);
        }
        else //  ret == 0
        {
            if ((uint)timer.elapsed() > max_poll_wait)
            {
                VERBOSE(VB_IMPORTANT, LOC_ERR + "Poll giving up");
                QMutexLocker locker(&lock);
                error = true;
                return true;
            }
        }
    }
    return retval;
#endif //!USING_MINGW
}
Exemple #26
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;
}
/** \fn ThreadedFileWriter::DiskLoop(void)
 *  \brief The thread run method that actually calls writes to disk.
 */
void ThreadedFileWriter::DiskLoop(void)
{
#ifndef USING_MINGW
    // don't exit program if file gets larger than quota limit..
    signal(SIGXFSZ, SIG_IGN);
#endif

    QMutexLocker locker(&buflock);

    // Even if the bytes buffered is less than the minimum write
    // size we do want to write to the OS buffers periodically.
    // This timer makes sure we do.
    MythTimer minWriteTimer;
    minWriteTimer.start();

    while (!in_dtor)
    {
        if (ignore_writes)
        {
            while (!writeBuffers.empty())
            {
                delete writeBuffers.front();
                writeBuffers.pop_front();
            }
            while (!emptyBuffers.empty())
            {
                delete emptyBuffers.front();
                emptyBuffers.pop_front();
            }
            bufferEmpty.wakeAll();
            bufferHasData.wait(locker.mutex());
            continue;
        }

        if (writeBuffers.empty())
        {
            bufferEmpty.wakeAll();
            bufferHasData.wait(locker.mutex(), 1000);
            TrimEmptyBuffers();
            continue;
        }

        int mwte = minWriteTimer.elapsed();
        if (!flush && (mwte < 250) && (totalBufferUse < kMinWriteSize))
        {
            bufferHasData.wait(locker.mutex(), 250 - mwte);
            TrimEmptyBuffers();
            continue;
        }

        TFWBuffer *buf = writeBuffers.front();
        writeBuffers.pop_front();
        totalBufferUse -= buf->data.size();
        minWriteTimer.start();

        //////////////////////////////////////////

        const void *data = &(buf->data[0]);
        uint sz = buf->data.size();

        bool write_ok = true;
        uint tot = 0;
        uint errcnt = 0;

        LOG(VB_FILE, LOG_DEBUG, LOC + QString("write(%1) cnt %2 total %3")
                .arg(sz).arg(writeBuffers.size())
                .arg(totalBufferUse));

        MythTimer writeTimer;
        writeTimer.start();

        while ((tot < sz) && !in_dtor)
        {
            locker.unlock();

            int ret = write(fd, (char *)data + tot, sz - tot);

            if (ret < 0)
            {
                if (errno == EAGAIN)
                {
                    LOG(VB_GENERAL, LOG_WARNING, LOC + "Got EAGAIN.");
                }
                else
                {
                    errcnt++;
                    LOG(VB_GENERAL, LOG_ERR, LOC + "File I/O " +
                        QString(" errcnt: %1").arg(errcnt) + ENO);
                }

                if ((errcnt >= 3) || (ENOSPC == errno) || (EFBIG == errno))
                {
                    locker.relock();
                    write_ok = false;
                    break;
                }
            }
            else
            {
                tot += ret;
            }

            locker.relock();

            if (!in_dtor)
                bufferHasData.wait(locker.mutex(), 50);
        }

        //////////////////////////////////////////

        buf->lastUsed = QDateTime::currentDateTime();
        emptyBuffers.push_back(buf);

        if (writeTimer.elapsed() > 1000)
        {
            LOG(VB_GENERAL, LOG_WARNING, LOC +
                QString("write(%1) cnt %2 total %3 -- took a long time, %4 ms")
                    .arg(sz).arg(writeBuffers.size())
                    .arg(totalBufferUse).arg(writeTimer.elapsed()));
        }

        if (!write_ok && ((EFBIG == errno) || (ENOSPC == errno)))
        {
            QString msg;
            switch (errno)
            {
                case EFBIG:
                    msg =
                        "Maximum file size exceeded by '%1'"
                        "\n\t\t\t"
                        "You must either change the process ulimits, configure"
                        "\n\t\t\t"
                        "your operating system with \"Large File\" support, "
                        "or use"
                        "\n\t\t\t"
                        "a filesystem which supports 64-bit or 128-bit files."
                        "\n\t\t\t"
                        "HINT: FAT32 is a 32-bit filesystem.";
                    break;
                case ENOSPC:
                    msg =
                        "No space left on the device for file '%1'"
                        "\n\t\t\t"
                        "file will be truncated, no further writing "
                        "will be done.";
                    break;
            }

            LOG(VB_GENERAL, LOG_ERR, LOC + msg.arg(filename));
            ignore_writes = true;
        }
    }
}
Exemple #28
0
bool DeviceReadBuffer::Poll(void) const
{
#ifdef USING_MINGW
# ifdef _MSC_VER
#  pragma message( "mingw DeviceReadBuffer::Poll" )
# else
#  warning mingw DeviceReadBuffer::Poll
# endif
    LOG(VB_GENERAL, LOG_ERR, LOC +
        "mingw DeviceReadBuffer::Poll is not implemented");
    return false;
#else
    bool retval = true;
    MythTimer timer;
    timer.start();

    int poll_cnt = 1;
    struct pollfd polls[2];
    memset(polls, 0, sizeof(polls));

    polls[0].fd      = _stream_fd;
    polls[0].events  = POLLIN | POLLPRI;
    polls[0].revents = 0;

    if (wake_pipe[0] >= 0)
    {
        poll_cnt = 2;
        polls[1].fd      = wake_pipe[0];
        polls[1].events  = POLLIN;
        polls[1].revents = 0;
    }

    while (true)
    {
        polls[0].revents = 0;
        polls[1].revents = 0;
        poll_cnt = (wake_pipe[0] >= 0) ? poll_cnt : 1;

        int timeout = max_poll_wait;
        if (1 == poll_cnt)
            timeout = 10;
        else if (poll_timeout_is_error)
            timeout = max((int)max_poll_wait - timer.elapsed(), 10);

        int ret = poll(polls, poll_cnt, timeout);

        if (polls[0].revents & POLLHUP)
        {
            LOG(VB_GENERAL, LOG_ERR, LOC + "poll eof (POLLHUP)");
            break;
        }
        else if (polls[0].revents & POLLNVAL)
        {
            LOG(VB_GENERAL, LOG_ERR, LOC + "poll error");
            error = true;
            return true;
        }

        if (!dorun || !IsOpen() || IsPauseRequested())
        {
            retval = false;
            break; // are we supposed to pause, stop, etc.
        }

        if (polls[0].revents & POLLPRI)
        {
            readerCB->PriorityEvent(polls[0].fd);
        }

        if (polls[0].revents & POLLIN)
        {
            if (ret > 0)
                break; // we have data to read :)
            else if (ret < 0)
            {
                if ((EOVERFLOW == errno))
                    break; // we have an error to handle

                if ((EAGAIN == errno) || (EINTR  == errno))
                    continue; // errors that tell you to try again

                usleep(2500 /*2.5 ms*/);
            }
            else //  ret == 0
            {
                if (poll_timeout_is_error &&
                    (timer.elapsed() >= (int)max_poll_wait))
                {
                    LOG(VB_GENERAL, LOG_ERR, LOC + "Poll giving up 1");
                    QMutexLocker locker(&lock);
                    error = true;
                    return true;
                }
            }
        }

        // Clear out any pending pipe reads
        if ((poll_cnt > 1) && (polls[1].revents & POLLIN))
        {
            char dummy[128];
            int cnt = (wake_pipe_flags[0] & O_NONBLOCK) ? 128 : 1;
            cnt = ::read(wake_pipe[0], dummy, cnt);
        }

        if (poll_timeout_is_error && (timer.elapsed() >= (int)max_poll_wait))
        {
            LOG(VB_GENERAL, LOG_ERR, LOC + "Poll giving up 2");
            QMutexLocker locker(&lock);
            error = true;
            return true;
        }
    }

    int e = timer.elapsed();
    if (e > (int)max_poll_wait)
    {
        LOG(VB_GENERAL, LOG_WARNING, LOC +
            QString("Poll took an unusually long time %1 ms")
            .arg(timer.elapsed()));
    }

    return retval;
#endif //!USING_MINGW
}
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;
}