/** \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; }
/** \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; }
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; }
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 ); }
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(); }
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); }
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); } }
/** \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; }
/** \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(); }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
/** * \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(); }
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 }
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; } } }
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; }