InteractiveTV::InteractiveTV(MythPlayer *nvp) : m_context(new MHIContext(this)), m_nvp(nvp) { Restart(0, 0, false); MHSetLogging(stdout, VERBOSE_LEVEL_CHECK(VB_MHEG, LOG_DEBUG) ? MHLogAll : VERBOSE_LEVEL_CHECK(VB_MHEG, LOG_ANY) ? MHLogError | MHLogWarning | MHLogNotifications /*| MHLogLinks | MHLogActions | MHLogDetail*/ : MHLogError | MHLogWarning ); }
/** \fn LiveTVChain::SwitchTo(int) * \brief Sets the recording to switch to. * \param num Index of recording to switch to, -1 for last recording. */ void LiveTVChain::SwitchTo(int num) { QMutexLocker lock(&m_lock); LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("SwitchTo(%1)").arg(num)); int size = m_chain.count(); if ((num < 0) || (num >= size)) num = size - 1; if (m_curpos != num) { m_switchid = num; GetEntryAt(num, m_switchentry); } else LOG(VB_GENERAL, LOG_ERR, LOC + "SwitchTo() not switching to current"); if (VERBOSE_LEVEL_CHECK(VB_PLAYBACK, LOG_DEBUG)) { LiveTVChainEntry e; GetEntryAt(num, e); QString msg = QString("%1_%2") .arg(e.chanid).arg(e.starttime.toString("yyyyMMddhhmmss")); LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("Entry@%1: '%2')").arg(num).arg(msg)); } }
bool MSqlQuery::next() { bool result = QSqlQuery::next(); if (result && VERBOSE_LEVEL_CHECK(VB_DATABASE|VB_EXTRA)) { QString str; QSqlRecord record=QSqlQuery::record(); for ( long int i = 0; i<record.count(); i++ ) { if (!str.isEmpty()) str.append(", "); str.append(record.fieldName(i) + " = " + value(i).toString()); } LOG(VB_DATABASE, LOG_DEBUG, QString("MSqlQuery::next(%1) Result: \"%2\"") .arg(m_db->MSqlDatabase::GetConnectionName()) .arg(str)); } return result; }
bool MSqlQuery::seekDebug(const char *type, bool result, int where, bool relative) const { if (result && VERBOSE_LEVEL_CHECK(VB_DATABASE, LOG_DEBUG)) { QString str; QSqlRecord rec = record(); for (long int i = 0; i < rec.count(); i++) { if (!str.isEmpty()) str.append(", "); str.append(rec.fieldName(i) + " = " + value(i).toString()); } if (QString("seek")==type) { LOG(VB_DATABASE, LOG_DEBUG, QString("MSqlQuery::seek(%1,%2,%3) Result: \"%4\"") .arg(m_db->MSqlDatabase::GetConnectionName()) .arg(where).arg(relative) .arg(str)); } else { LOG(VB_DATABASE, LOG_DEBUG, QString("MSqlQuery::%1(%2) Result: \"%3\"") .arg(type).arg(m_db->MSqlDatabase::GetConnectionName()) .arg(str)); } } return result; }
/** \fn LiveTVChain::SwitchTo(int) * \brief Sets the recording to switch to. * \param num Index of recording to switch to, -1 for last recording. */ void LiveTVChain::SwitchTo(int num) { QMutexLocker lock(&m_lock); VERBOSE(VB_PLAYBACK, LOC + "SwitchTo("<<num<<")"); int size = m_chain.count(); if ((num < 0) || (num >= size)) num = size - 1; if (m_curpos != num) { m_switchid = num; GetEntryAt(num, m_switchentry); } else VERBOSE(VB_IMPORTANT, LOC + "SwitchTo() not switching to current"); if (VERBOSE_LEVEL_CHECK(VB_PLAYBACK)) { LiveTVChainEntry e; GetEntryAt(num, e); QString msg = QString("%1_%2") .arg(e.chanid).arg(e.starttime.toString("yyyyMMddhhmmss")); VERBOSE(VB_PLAYBACK, LOC + "Entry@"<<num<<": '"<<msg<<"'"); } }
bool MSqlQuery::exec() { // Database connection down. Try to restart it, give up if it's still // down if (!m_db) { // Database structure's been deleted return false; } if (!m_db->isOpen() && !m_db->Reconnect()) { LOG(VB_GENERAL, LOG_INFO, "MySQL server disconnected"); return false; } bool result = QSqlQuery::exec(); // if the query failed with "MySQL server has gone away" // Close and reopen the database connection and retry the query if it // connects again if (!result && QSqlQuery::lastError().number() == 2006 && m_db->Reconnect()) result = QSqlQuery::exec(); if (VERBOSE_LEVEL_CHECK(VB_DATABASE) && logLevel <= LOG_DEBUG) { QString str = lastQuery(); // Database logging will cause an infinite loop here if not filtered // out if (!str.startsWith("INSERT INTO logging ")) { // Sadly, neither executedQuery() nor lastQuery() display // the values in bound queries against a MySQL5 database. // So, replace the named placeholders with their values. QMapIterator<QString, QVariant> b = boundValues(); while (b.hasNext()) { b.next(); str.replace(b.key(), '\'' + b.value().toString() + '\''); } LOG(VB_DATABASE, LOG_DEBUG, QString("MSqlQuery::exec(%1) %2%3") .arg(m_db->MSqlDatabase::GetConnectionName()).arg(str) .arg(isSelect() ? QString(" <<<< Returns %1 row(s)") .arg(size()) : QString())); } } return result; }
void SSDPCache::Dump() { int nCount = 0; if (VERBOSE_LEVEL_CHECK(VB_UPNP)) { Lock(); // ---------------------------------------------------------------------- // Build List of items to be removed // ---------------------------------------------------------------------- VERBOSE( VB_UPNP, "===============================================================================" ); VERBOSE( VB_UPNP, QString( " URI (type) - Found: %1 Entries - %2 have been Allocated. " ) .arg( m_cache.count() ) .arg( SSDPCacheEntries::g_nAllocated )); VERBOSE( VB_UPNP, " \t\tUSN (unique id)\t\t | Expires\t | Location" ); VERBOSE( VB_UPNP, "-------------------------------------------------------------------------------" ); for (SSDPCacheEntriesMap::Iterator it = m_cache.begin(); it != m_cache.end(); ++it ) { SSDPCacheEntries *pEntries = *it; if (pEntries != NULL) { VERBOSE( VB_UPNP, it.key() ); pEntries->Lock(); EntryMap *pMap = pEntries->GetEntryMap(); for (EntryMap::Iterator itEntry = pMap->begin(); itEntry != pMap->end(); ++itEntry ) { DeviceLocation *pEntry = *itEntry; if (pEntry != NULL) { nCount++; pEntry->AddRef(); VERBOSE( VB_UPNP, QString( " * \t\t%1\t | %2\t | %3 " ) .arg( pEntry->m_sUSN ) .arg( pEntry->ExpiresInSecs() ) .arg( pEntry->m_sLocation )); pEntry->Release(); } } VERBOSE( VB_UPNP, " "); pEntries->Unlock(); } } VERBOSE( VB_UPNP, "-------------------------------------------------------------------------------" ); VERBOSE( VB_UPNP, QString( " Found: %1 Entries - %2 have been Allocated. " ) .arg( nCount ) .arg( DeviceLocation::g_nAllocated )); VERBOSE( VB_UPNP, "===============================================================================" ); Unlock(); } }
bool MSqlQuery::exec() { if (!m_db) { // Database structure's been deleted return false; } if (m_last_prepared_query.isEmpty()) { LOG(VB_GENERAL, LOG_ERR, "MSqlQuery::exec(void) called without a prepared query."); return false; } #if DEBUG_RECONNECT if (random() < RAND_MAX / 50) { LOG(VB_GENERAL, LOG_INFO, "MSqlQuery disconnecting DB to test reconnection logic"); m_db->m_db.close(); } #endif // Database connection down. Try to restart it, give up if it's still // down if (!m_db->isOpen() && !Reconnect()) { LOG(VB_GENERAL, LOG_INFO, "MySQL server disconnected"); return false; } QElapsedTimer timer; timer.start(); bool result = QSqlQuery::exec(); qint64 elapsed = timer.elapsed(); // if the query failed with "MySQL server has gone away" // Close and reopen the database connection and retry the query if it // connects again if (!result && QSqlQuery::lastError().number() == 2006 && Reconnect()) result = QSqlQuery::exec(); if (!result) { QString err = MythDB::GetError("MSqlQuery", *this); MSqlBindings tmp = QSqlQuery::boundValues(); bool has_null_strings = false; for (MSqlBindings::iterator it = tmp.begin(); it != tmp.end(); ++it) { if (it->type() != QVariant::String) continue; if (it->isNull() || it->toString().isNull()) { has_null_strings = true; *it = QVariant(QString("")); } } if (has_null_strings) { bindValues(tmp); timer.restart(); result = QSqlQuery::exec(); elapsed = timer.elapsed(); } if (result) { LOG(VB_GENERAL, LOG_ERR, QString("Original query failed, but resend with empty " "strings in place of NULL strings worked. ") + "\n" + err); } } if (VERBOSE_LEVEL_CHECK(VB_DATABASE, LOG_INFO)) { QString str = lastQuery(); // Database logging will cause an infinite loop here if not filtered // out if (!str.startsWith("INSERT INTO logging ")) { // Sadly, neither executedQuery() nor lastQuery() display // the values in bound queries against a MySQL5 database. // So, replace the named placeholders with their values. QMapIterator<QString, QVariant> b = boundValues(); while (b.hasNext()) { b.next(); str.replace(b.key(), '\'' + b.value().toString() + '\''); } LOG(VB_DATABASE, LOG_INFO, QString("MSqlQuery::exec(%1) %2%3%4") .arg(m_db->MSqlDatabase::GetConnectionName()).arg(str) .arg(QString(" <<<< Took %1ms").arg(QString::number(elapsed))) .arg(isSelect() ? QString(", Returned %1 row(s)") .arg(size()) : QString())); } } return result; }
bool AudioInputALSA::PrepHwParams(void) { snd_pcm_hw_params_t* hwparams; snd_pcm_hw_params_alloca(&hwparams); if (AlsaBad(snd_pcm_hw_params_any(pcm_handle, hwparams), "failed to init hw params")) return false; snd_pcm_access_t axs = SND_PCM_ACCESS_RW_INTERLEAVED; //always? if (AlsaBad(snd_pcm_hw_params_set_access(pcm_handle, hwparams, axs), "failed to set interleaved rw io")) return false; snd_pcm_format_t format = (m_audio_sample_bits > 8) ? SND_PCM_FORMAT_S16 : SND_PCM_FORMAT_U8; if (AlsaBad(snd_pcm_hw_params_set_format(pcm_handle, hwparams, format), QString("failed to set sample format %1") .arg(snd_pcm_format_description(format)))) return false; if (VERBOSE_LEVEL_CHECK(VB_AUDIO, LOG_DEBUG)) { uint min_chans, max_chans; if(AlsaBad(snd_pcm_hw_params_get_channels_min(hwparams, &min_chans), QString("unable to get min channel count"))) min_chans = 0; if(AlsaBad(snd_pcm_hw_params_get_channels_max(hwparams, &max_chans), QString("unable to get max channel count"))) max_chans = 0; LOG(VB_AUDIO, LOG_DEBUG, LOC_DEV + QString("min channels %1, max channels %2, myth requests %3") .arg(min_chans).arg(max_chans).arg(m_audio_channels)); } if (AlsaBad(snd_pcm_hw_params_set_channels(pcm_handle, hwparams, m_audio_channels), QString("failed to set channels to %1") .arg(m_audio_channels))) { return false; } if (AlsaBad(snd_pcm_hw_params_set_rate(pcm_handle, hwparams, m_audio_sample_rate, 0), QString("failed to set sample rate %1") .arg(m_audio_sample_rate))) { uint rate_num = 0; uint rate_den = 0; if (!AlsaBad(snd_pcm_hw_params_get_rate_numden(hwparams, &rate_num, &rate_den), "snd_pcm_hw_params_get_rate_numden failed")) if (m_audio_sample_rate != (int)(rate_num / rate_den)) LOG(VB_GENERAL, LOG_ERR, LOC_DEV + QString("device reports sample rate as %1") .arg(rate_num / rate_den)); return false; } uint buffer_time = 64000; // 64 msec uint period_time = buffer_time / 4; if (AlsaBad(snd_pcm_hw_params_set_period_time_near(pcm_handle, hwparams, &period_time, NULL), "failed to set period time")) return false; if (AlsaBad(snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams, &buffer_time, NULL), "failed to set buffer time")) return false; if (AlsaBad(snd_pcm_hw_params_get_period_size(hwparams, &period_size, NULL), "failed to get period size")) return false; if (AlsaBad(snd_pcm_hw_params (pcm_handle, hwparams), "failed to set hwparams")) return false; myth_block_bytes = snd_pcm_frames_to_bytes(pcm_handle, period_size); LOG(VB_AUDIO, LOG_INFO, LOC_DEV + QString("channels %1, sample rate %2, buffer_time %3 msec, period " "size %4").arg(m_audio_channels) .arg(m_audio_sample_rate).arg(buffer_time / 1000.0, -1, 'f', 1) .arg(period_size)); LOG(VB_AUDIO, LOG_DEBUG, LOC_DEV + QString("myth block size %1") .arg(myth_block_bytes)); return true; }
void ChannelScannerCLI::HandleEvent(const ScannerEvent *scanEvent) { if ((scanEvent->type() == ScannerEvent::ScanComplete) || (scanEvent->type() == ScannerEvent::ScanShutdown)) { cout<<endl; if (scanEvent->type() == ScannerEvent::ScanShutdown) cerr<<"HandleEvent(void) -- scan shutdown"<<endl; else cerr<<"HandleEvent(void) -- scan complete"<<endl; ScanDTVTransportList transports; if (sigmonScanner) { sigmonScanner->StopScanner(); transports = sigmonScanner->GetChannelList(); } Teardown(); if (!transports.empty()) Process(transports); done = true; QCoreApplication::exit(0); } else if (scanEvent->type() == ScannerEvent::AppendTextToLog) status_last_log = scanEvent->strValue(); else if (scanEvent->type() == ScannerEvent::SetStatusText) status_text = scanEvent->strValue(); else if (scanEvent->type() == ScannerEvent::SetStatusTitleText) ; else if (scanEvent->type() == ScannerEvent::SetPercentComplete) status_complete = scanEvent->intValue(); else if (scanEvent->type() == ScannerEvent::SetStatusRotorPosition) ; else if (scanEvent->type() == ScannerEvent::SetStatusSignalLock) status_lock = scanEvent->intValue(); else if (scanEvent->type() == ScannerEvent::SetStatusSignalToNoise) status_snr = scanEvent->intValue() / 65535.0; else if (scanEvent->type() == ScannerEvent::SetStatusSignalStrength) ; //cout<<"HERE<"<<print_verbose_messages<<">"<<endl; QString msg; if (VERBOSE_LEVEL_NONE || VERBOSE_LEVEL_CHECK(VB_CHANSCAN)) { msg.sprintf("%3i%% S/N %3.1f %s : %s (%s) %20s", status_complete, status_snr, (status_lock) ? "l" : "L", status_text.toAscii().constData(), status_last_log.toAscii().constData(), ""); } //cout<<msg.toAscii().constData()<<endl; if (VERBOSE_LEVEL_CHECK(VB_CHANSCAN)) { static QString old_msg; if (msg != old_msg) { VERBOSE(VB_CHANSCAN, LOC + msg); old_msg = msg; } } else if (VERBOSE_LEVEL_NONE) { if (msg.length() > 80) msg = msg.left(77) + "..."; cout<<"\r"<<msg.toAscii().constData()<<"\r"; cout<<flush; } }
/** * \brief Tunes the card to a frequency but does not deal with PIDs. * * This is used by DVB Channel Scanner, the EIT Parser, and by TVRec. * * \param tuning Info on transport to tune to * \param inputid Optional, forces specific input (for DiSEqC) * \param force_reset If true, frequency tuning is done * even if it should not be needed. * \param same_input Optional, doesn't change input (for retuning). * \return true on success, false on failure */ bool DVBChannel::Tune(const DTVMultiplex &tuning, uint inputid, bool force_reset, bool same_input) { QMutexLocker lock(&tune_lock); QMutexLocker locker(&hw_lock); DVBChannel *master = GetMasterLock(); if (master != this) { LOG(VB_CHANNEL, LOG_INFO, LOC + "tuning on slave channel"); SetSIStandard(tuning.sistandard); bool ok = master->Tune(tuning, inputid, force_reset, false); ReturnMasterLock(master); return ok; } ReturnMasterLock(master); // if we're the master we don't need this lock.. int intermediate_freq = 0; bool can_fec_auto = false; bool reset = (force_reset || first_tune); if (tunerType.IsDiSEqCSupported() && !diseqc_tree) { LOG(VB_GENERAL, LOG_ERR, LOC + "DVB-S needs device tree for LNB handling"); return false; } desired_tuning = tuning; if (fd_frontend < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): Card not open!"); return false; } // Remove any events in queue before tuning. drain_dvb_events(fd_frontend); // send DVB-S setup if (diseqc_tree) { // configure for new input if (!same_input) diseqc_settings.Load(inputid); // execute diseqc commands if (!diseqc_tree->Execute(diseqc_settings, tuning)) { LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): Failed to setup DiSEqC devices"); return false; } // retrieve actual intermediate frequency DiSEqCDevLNB *lnb = diseqc_tree->FindLNB(diseqc_settings); if (!lnb) { LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): No LNB for this configuration"); return false; } if (lnb->GetDeviceID() != last_lnb_dev_id) { last_lnb_dev_id = lnb->GetDeviceID(); // make sure we tune to frequency, if the lnb has changed reset = first_tune = true; } intermediate_freq = lnb->GetIntermediateFrequency( diseqc_settings, tuning); // if card can auto-FEC, use it -- sometimes NITs are inaccurate if (capabilities & FE_CAN_FEC_AUTO) can_fec_auto = true; // Check DVB-S intermediate frequency here since it requires a fully // initialized diseqc tree CheckFrequency(intermediate_freq); } LOG(VB_CHANNEL, LOG_INFO, LOC + "Old Params: " + prev_tuning.toString() + "\n\t\t\t" + LOC + "New Params: " + tuning.toString()); // DVB-S is in kHz, other DVB is in Hz bool is_dvbs = ((DTVTunerType::kTunerTypeDVBS1 == tunerType) || (DTVTunerType::kTunerTypeDVBS2 == tunerType)); int freq_mult = (is_dvbs) ? 1 : 1000; QString suffix = (is_dvbs) ? "kHz" : "Hz"; if (reset || !prev_tuning.IsEqual(tunerType, tuning, 500 * freq_mult)) { LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Tune(): Tuning to %1%2") .arg(intermediate_freq ? intermediate_freq : tuning.frequency) .arg(suffix)); #if DVB_API_VERSION >=5 if (DTVTunerType::kTunerTypeDVBS2 == tunerType) { struct dtv_property p_clear; struct dtv_properties cmdseq_clear; p_clear.cmd = DTV_CLEAR; cmdseq_clear.num = 1; cmdseq_clear.props = &p_clear; if ((ioctl(fd_frontend, FE_SET_PROPERTY, &cmdseq_clear)) < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): Clearing DTV properties cache failed." + ENO); return false; } struct dtv_properties *cmds = dtvmultiplex_to_dtvproperties( tunerType, tuning, intermediate_freq, can_fec_auto); if (!cmds) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to convert DTVMultiplex to DTV_PROPERTY sequence"); return false; } if (VERBOSE_LEVEL_CHECK(VB_CHANNEL, LOG_DEBUG)) { for (uint i = 0; i < cmds->num; i++) { LOG(VB_CHANNEL, LOG_DEBUG, LOC + QString("prop %1: cmd = %2, data %3") .arg(i).arg(cmds->props[i].cmd) .arg(cmds->props[i].u.data)); } } int res = ioctl(fd_frontend, FE_SET_PROPERTY, cmds); free(cmds->props); free(cmds); if (res < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): Setting Frontend tuning parameters failed." + ENO); return false; } } else #endif { struct dvb_frontend_parameters params = dtvmultiplex_to_dvbparams( tunerType, tuning, intermediate_freq, can_fec_auto); if (ioctl(fd_frontend, FE_SET_FRONTEND, ¶ms) < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): Setting Frontend tuning parameters failed." + ENO); return false; } } // Extra delay to add for broken DVB drivers if (tuning_delay) usleep(tuning_delay * 1000); wait_for_backend(fd_frontend, 5 /* msec */); prev_tuning = tuning; first_tune = false; } SetSIStandard(tuning.sistandard); LOG(VB_CHANNEL, LOG_INFO, LOC + "Tune(): Frequency tuning successful."); return true; }
static MythImage *LoadImage(MythPainter *painter, // Must be a copy for thread safety ImageProperties imProps, ImageCacheMode cacheMode, // Included only to check address, could be // replaced by generating a unique value for // each MythUIImage object? const MythUIImage *parent, bool &aborted, MythImageReader *imageReader = NULL) { QString cacheKey = GenImageLabel(imProps); if (!PreLoad(cacheKey, parent)) { aborted = true; return NULL; } QString filename = imProps.filename; MythImage *image = NULL; bool bResize = false; bool bFoundInCache = false; int w = -1; int h = -1; if (!imProps.forceSize.isNull()) { if (imProps.forceSize.width() != -1) w = imProps.forceSize.width(); if (imProps.forceSize.height() != -1) h = imProps.forceSize.height(); bResize = true; } if (!imageReader) { image = GetMythUI()->LoadCacheImage(filename, cacheKey, painter, cacheMode); } if (image) { if (VERBOSE_LEVEL_CHECK(VB_GUI | VB_FILE, LOG_INFO)) { image->IncrRef(); int cnt = image->DecrRef(); LOG(VB_GUI | VB_FILE, LOG_INFO, QString("ImageLoader::LoadImage(%1) Found in cache, " "RefCount = %2") .arg(cacheKey).arg(cnt)); } if (imProps.isReflected) image->setIsReflected(true); if (imProps.isOriented) image->setIsOriented(true); bFoundInCache = true; } else { LOG(VB_GUI | VB_FILE, LOG_INFO, QString("ImageLoader::LoadImage(%1) NOT Found in cache. " "Loading Directly").arg(cacheKey)); image = painter->GetFormatImage(); bool ok = false; if (imageReader) ok = image->Load(imageReader); else ok = image->Load(filename); if (!ok) { image->DecrRef(); image = NULL; } } if (image && image->isNull()) { LOG(VB_GUI | VB_FILE, LOG_INFO, QString("ImageLoader::LoadImage(%1) Image is NULL") .arg(filename)); image->DecrRef(); image = NULL; } if (image && !bFoundInCache) { if (imProps.isReflected) image->Reflect(imProps.reflectAxis, imProps.reflectShear, imProps.reflectScale, imProps.reflectLength, imProps.reflectSpacing); if (imProps.isGreyscale) image->ToGreyscale(); if (imProps.isOriented) image->Orientation(imProps.orientation); // Even if an explicit size wasn't defined this image may still need // to be scaled because of a difference between the theme resolution // and the screen resolution. We want to avoid scaling twice. if (!bResize && imProps.isThemeImage) { float wmult; // Width multipler float hmult; // Height multipler GetMythUI()->GetScreenSettings(wmult, hmult); if (wmult != 1.0f || hmult != 1.0f) { w = image->size().width() * wmult; h = image->size().height() * hmult; bResize = true; } } if (bResize) image->Resize(QSize(w, h), imProps.preserveAspect); if (imProps.isMasked) { QRect imageArea = image->rect(); QRect maskArea = imProps.GetMaskImageRect(); // Crop the mask to the image int x = 0; int y = 0; if (maskArea.width() > imageArea.width()) x = (maskArea.width() - imageArea.width()) / 2; if (maskArea.height() > imageArea.height()) y = (maskArea.height() - imageArea.height()) / 2; if (x > 0 || y > 0) imageArea.translate(x, y); QImage mask = imProps.GetMaskImageSubset(imageArea); image->setAlphaChannel(mask.alphaChannel()); } if (!imageReader) GetMythUI()->CacheImage(cacheKey, image); } if (image) image->SetChanged(); PostLoad(cacheKey); return image; }
void MythSocketThread::run(void) { VERBOSE(VB_SOCKET, "MythSocketThread: readyread thread start"); QMutexLocker locker(&m_readyread_lock); m_readyread_started_wait.wakeAll(); while (m_readyread_run) { VERBOSE(VB_SOCKET|VB_EXTRA, "ProcessAddRemoveQueues"); ProcessAddRemoveQueues(); VERBOSE(VB_SOCKET|VB_EXTRA, "Construct FD_SET"); // construct FD_SET for all connected and unlocked sockets... int maxfd = -1; fd_set rfds; FD_ZERO(&rfds); QList<MythSocket*>::const_iterator it = m_readyread_list.begin(); for (; it != m_readyread_list.end(); ++it) { if (!(*it)->TryLock(false)) continue; if ((*it)->state() == MythSocket::Connected && !(*it)->m_notifyread) { FD_SET((*it)->socket(), &rfds); maxfd = std::max((*it)->socket(), maxfd); } (*it)->Unlock(false); } // There are no unlocked sockets, wait for event before we continue.. if (maxfd < 0) { VERBOSE(VB_SOCKET|VB_EXTRA, "Empty FD_SET, sleeping"); if (m_readyread_wait.wait(&m_readyread_lock)) VERBOSE(VB_SOCKET|VB_EXTRA, "Empty FD_SET, woken up"); else VERBOSE(VB_SOCKET|VB_EXTRA, "Empty FD_SET, timed out"); continue; } int rval = 0; if (m_readyread_pipe[0] >= 0) { // Clear out any pending pipe reads, we have already taken care of // this event above under the m_readyread_lock. char dummy[128]; if (m_readyread_pipe_flags[0] & O_NONBLOCK) { rval = ::read(m_readyread_pipe[0], dummy, 128); FD_SET(m_readyread_pipe[0], &rfds); maxfd = std::max(m_readyread_pipe[0], maxfd); } // also exit select on exceptions on same descriptors fd_set efds; memcpy(&efds, &rfds, sizeof(fd_set)); // The select waits forever for data, so if we need to process // anything else we need to write to m_readyread_pipe[1].. // We unlock the ready read lock, because we don't need it // and this will allow WakeReadyReadThread() to run.. m_readyread_lock.unlock(); VERBOSE(VB_SOCKET|VB_EXTRA, "Waiting on select.."); rval = select(maxfd + 1, &rfds, NULL, &efds, NULL); VERBOSE(VB_SOCKET|VB_EXTRA, "Got data on select"); m_readyread_lock.lock(); if (rval > 0 && FD_ISSET(m_readyread_pipe[0], &rfds)) { int ret = ::read(m_readyread_pipe[0], dummy, 128); if (ret < 0) { VERBOSE(VB_SOCKET|VB_EXTRA, "Strange.. failed to read event pipe"); } } } else { VERBOSE(VB_SOCKET|VB_EXTRA, "Waiting on select.. (no pipe)"); // also exit select on exceptions on same descriptors fd_set efds; memcpy(&efds, &rfds, sizeof(fd_set)); // Unfortunately, select on a pipe is not supported on all // platforms. So we fallback to a loop that instead times out // of select and checks for wakeAll event. while (!rval) { struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = kShortWait * 1000; rval = select(maxfd + 1, &rfds, NULL, &efds, &timeout); if (!rval) m_readyread_wait.wait(&m_readyread_lock, kShortWait); } VERBOSE(VB_SOCKET|VB_EXTRA, "Got data on select (no pipe)"); } if (rval <= 0) { if (rval == 0) { // Note: This should never occur when using pipes. When there // is no error there should be data in at least one fd.. VERBOSE(VB_SOCKET|VB_EXTRA, "MythSocketThread: select timeout"); } else VERBOSE(VB_SOCKET, "MythSocketThread: select returned error" + ENO); m_readyread_wait.wait(&m_readyread_lock, kShortWait); continue; } // ReadyToBeRead allows calls back into the socket so we need // to release the lock for a little while. // since only this loop updates m_readyread_list this is safe. m_readyread_lock.unlock(); // Actually read some data! This is a form of co-operative // multitasking so the ready read handlers should be quick.. uint downref_tm = 0; if (!m_readyread_downref_list.empty()) { VERBOSE(VB_SOCKET|VB_EXTRA, "Deleting stale sockets"); QTime tm = QTime::currentTime(); for (it = m_readyread_downref_list.begin(); it != m_readyread_downref_list.end(); ++it) { (*it)->DownRef(); } m_readyread_downref_list.clear(); downref_tm = tm.elapsed(); } VERBOSE(VB_SOCKET|VB_EXTRA, "Processing ready reads"); QMap<uint,uint> timers; QTime tm = QTime::currentTime(); it = m_readyread_list.begin(); for (; it != m_readyread_list.end() && m_readyread_run; ++it) { if (!(*it)->TryLock(false)) continue; int socket = (*it)->socket(); if (socket >= 0 && (*it)->state() == MythSocket::Connected && FD_ISSET(socket, &rfds)) { QTime rrtm = QTime::currentTime(); ReadyToBeRead(*it); timers[socket] = rrtm.elapsed(); } (*it)->Unlock(false); } if (VERBOSE_LEVEL_CHECK(VB_SOCKET|VB_EXTRA)) { QString rep = QString("Total read time: %1ms, on sockets") .arg(tm.elapsed()); QMap<uint,uint>::const_iterator it = timers.begin(); for (; it != timers.end(); ++it) rep += QString(" {%1,%2ms}").arg(it.key()).arg(*it); if (downref_tm) rep += QString(" {downref, %1ms}").arg(downref_tm); VERBOSE(VB_SOCKET|VB_EXTRA, QString("MythSocketThread: ") + rep); } m_readyread_lock.lock(); VERBOSE(VB_SOCKET|VB_EXTRA, "Reacquired ready read lock"); } VERBOSE(VB_SOCKET, "MythSocketThread: readyread thread exit"); }
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; }
// pure virtual bool CdDecoder::initialize() { if (m_inited) return true; m_inited = m_user_stop = m_finish = false; m_freq = m_bitrate = 0L; m_stat = DecoderEvent::Error; m_chan = 0; m_seekTime = -1.; if (output()) output()->PauseUntilBuffered(); QFile* file = dynamic_cast< QFile* >(input()); // From QIODevice* if (file) { setFilename(file->fileName()); m_tracknum = getFilename().section('.', 0, 0).toUInt(); } QMutexLocker lock(&getCdioMutex()); m_cdio = openCdio(m_devicename); if (!m_cdio) return false; m_start = cdio_get_track_lsn(m_cdio, m_tracknum); m_end = cdio_get_track_last_lsn(m_cdio, m_tracknum); if (CDIO_INVALID_LSN == m_start || CDIO_INVALID_LSN == m_end) { LOG(VB_MEDIA, LOG_INFO, "CdDecoder: No tracks on " + m_devicename); cdio_destroy(m_cdio), m_cdio = 0; return false; } LOG(VB_MEDIA, LOG_DEBUG, QString("CdDecoder track=%1 lsn start=%2 end=%3") .arg(m_tracknum).arg(m_start).arg(m_end)); m_curpos = m_start; m_device = cdio_cddap_identify_cdio(m_cdio, 0, NULL); if (NULL == m_device) { LOG(VB_GENERAL, LOG_ERR, QString("Error: CdDecoder: cdio_cddap_identify(%1) failed") .arg(m_devicename)); cdio_destroy(m_cdio), m_cdio = 0; return false; } cdio_cddap_verbose_set(m_device, VERBOSE_LEVEL_CHECK(VB_MEDIA, LOG_ANY) ? CDDA_MESSAGE_PRINTIT : CDDA_MESSAGE_FORGETIT, VERBOSE_LEVEL_CHECK(VB_MEDIA, LOG_DEBUG) ? CDDA_MESSAGE_PRINTIT : CDDA_MESSAGE_FORGETIT); if (DRIVER_OP_SUCCESS == cdio_cddap_open(m_device)) { // cdio_get_track_last_lsn is unreliable on discs with data at end lsn_t end2 = cdio_cddap_track_lastsector(m_device, m_tracknum); if (end2 < m_end) { LOG(VB_MEDIA, LOG_INFO, QString("CdDecoder: trim last lsn from %1 to %2") .arg(m_end).arg(end2)); m_end = end2; } m_paranoia = cdio_paranoia_init(m_device); if (NULL != m_paranoia) { cdio_paranoia_modeset(m_paranoia, PARANOIA_MODE_DISABLE); (void)cdio_paranoia_seek(m_paranoia, m_start, SEEK_SET); } else { LOG(VB_GENERAL, LOG_ERR, "Warn: CD reading with paranoia is disabled"); } } else { LOG(VB_GENERAL, LOG_ERR, QString("Warn: drive '%1' is not cdda capable"). arg(m_devicename)); } int chnls = cdio_get_track_channels(m_cdio, m_tracknum); m_chan = chnls > 0 ? chnls : 2; m_freq = kSamplesPerSec; if (output()) { const AudioSettings settings(FORMAT_S16, m_chan, CODEC_ID_PCM_S16LE, m_freq, false /* AC3/DTS passthru */); output()->Reconfigure(settings); output()->SetSourceBitrate(m_freq * m_chan * 16); } // 20ms worth m_bks = (m_freq * m_chan * 2) / 50; m_bksFrames = m_freq / 50; // decode 8 bks worth of samples each time we need more m_decodeBytes = m_bks << 3; m_output_buf = reinterpret_cast< char* >( ::av_malloc(m_decodeBytes + CDIO_CD_FRAMESIZE_RAW * 2)); m_output_at = 0; setCDSpeed(2); m_inited = true; return m_inited; }
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; }
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; }
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; }