|
MythTV
0.26-pre
|
00001 /* -*- Mode: c++ -*- 00002 * vim: set expandtab tabstop=4 shiftwidth=4: 00003 * 00004 * Original Project 00005 * MythTV http://www.mythtv.org 00006 * 00007 * Copyright (c) 2004, 2005 John Pullan <john@pullan.org> 00008 * Copyright (c) 2005 - 2007 Daniel Kristjansson 00009 * 00010 * Description: 00011 * Collection of classes to provide channel scanning functionallity 00012 * 00013 * This program is free software; you can redistribute it and/or 00014 * modify it under the terms of the GNU General Public License 00015 * as published by the Free Software Foundation; either version 2 00016 * of the License, or (at your option) any later version. 00017 * 00018 * This program is distributed in the hope that it will be useful, 00019 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00021 * GNU General Public License for more details. 00022 * 00023 * You should have received a copy of the GNU General Public License 00024 * along with this program; if not, write to the Free Software 00025 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00026 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html 00027 * 00028 */ 00029 00030 #include <algorithm> 00031 using namespace std; 00032 00033 #include "analogsignalmonitor.h" 00034 #include "iptvchannelfetcher.h" 00035 #include "dvbsignalmonitor.h" 00036 #include "scanwizardconfig.h" 00037 #include "channelscan_sm.h" 00038 #include "channelscanner.h" 00039 #include "hdhrchannel.h" 00040 #include "scanmonitor.h" 00041 #include "asichannel.h" 00042 #include "dvbchannel.h" 00043 #include "v4lchannel.h" 00044 #include "cardutil.h" 00045 00046 #define LOC QString("ChScan: ") 00047 00048 ChannelScanner::ChannelScanner() : 00049 scanMonitor(NULL), channel(NULL), sigmonScanner(NULL), freeboxScanner(NULL), 00050 freeToAirOnly(false), serviceRequirements(kRequireAV) 00051 { 00052 } 00053 00054 ChannelScanner::~ChannelScanner() 00055 { 00056 Teardown(); 00057 00058 if (scanMonitor) 00059 { 00060 scanMonitor->deleteLater(); 00061 scanMonitor = NULL; 00062 } 00063 } 00064 00065 void ChannelScanner::Teardown(void) 00066 { 00067 if (sigmonScanner) 00068 { 00069 delete sigmonScanner; 00070 sigmonScanner = NULL; 00071 } 00072 00073 if (channel) 00074 { 00075 delete channel; 00076 channel = NULL; 00077 } 00078 00079 #ifdef USING_IPTV 00080 if (freeboxScanner) 00081 { 00082 freeboxScanner->Stop(); 00083 delete freeboxScanner; 00084 freeboxScanner = NULL; 00085 } 00086 #endif // USING_IPTV 00087 00088 if (scanMonitor) 00089 { 00090 scanMonitor->deleteLater(); 00091 scanMonitor = NULL; 00092 } 00093 } 00094 00095 // full scan of existing transports broken 00096 // existing transport scan broken 00097 void ChannelScanner::Scan( 00098 int scantype, 00099 uint cardid, 00100 const QString &inputname, 00101 uint sourceid, 00102 bool do_ignore_signal_timeout, 00103 bool do_follow_nit, 00104 bool do_test_decryption, 00105 bool do_fta_only, 00106 ServiceRequirements service_requirements, 00107 // stuff needed for particular scans 00108 uint mplexid /* TransportScan */, 00109 const QMap<QString,QString> &startChan /* NITAddScan */, 00110 const QString &freq_std /* FullScan */, 00111 const QString &mod /* FullScan */, 00112 const QString &tbl /* FullScan */, 00113 const QString &tbl_start /* FullScan optional */, 00114 const QString &tbl_end /* FullScan optional */) 00115 { 00116 freeToAirOnly = do_fta_only; 00117 serviceRequirements = service_requirements; 00118 00119 PreScanCommon(scantype, cardid, inputname, 00120 sourceid, do_ignore_signal_timeout, do_test_decryption); 00121 00122 LOG(VB_CHANSCAN, LOG_INFO, LOC + "Scan()"); 00123 00124 if (!sigmonScanner) 00125 { 00126 LOG(VB_CHANSCAN, LOG_ERR, LOC + "Scan(): scanner does not exist..."); 00127 return; 00128 } 00129 00130 sigmonScanner->StartScanner(); 00131 scanMonitor->ScanUpdateStatusText(""); 00132 00133 bool ok = false; 00134 00135 if ((ScanTypeSetting::FullScan_ATSC == scantype) || 00136 (ScanTypeSetting::FullScan_DVBC == scantype) || 00137 (ScanTypeSetting::FullScan_DVBT == scantype) || 00138 (ScanTypeSetting::FullScan_Analog == scantype)) 00139 { 00140 LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("ScanTransports(%1, %2, %3)") 00141 .arg(freq_std).arg(mod).arg(tbl)); 00142 00143 // HACK HACK HACK -- begin 00144 // if using QAM we may need additional time... (at least with HD-3000) 00145 if ((mod.left(3).toLower() == "qam") && 00146 (sigmonScanner->GetSignalTimeout() < 1000)) 00147 { 00148 sigmonScanner->SetSignalTimeout(1000); 00149 } 00150 // HACK HACK HACK -- end 00151 00152 sigmonScanner->SetAnalog(ScanTypeSetting::FullScan_Analog == scantype); 00153 00154 ok = sigmonScanner->ScanTransports( 00155 sourceid, freq_std, mod, tbl, tbl_start, tbl_end); 00156 } 00157 else if ((ScanTypeSetting::NITAddScan_DVBT == scantype) || 00158 (ScanTypeSetting::NITAddScan_DVBS == scantype) || 00159 (ScanTypeSetting::NITAddScan_DVBS2 == scantype) || 00160 (ScanTypeSetting::NITAddScan_DVBC == scantype)) 00161 { 00162 LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanTransports()"); 00163 00164 ok = sigmonScanner->ScanTransportsStartingOn(sourceid, startChan); 00165 } 00166 else if (ScanTypeSetting::FullTransportScan == scantype) 00167 { 00168 LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("ScanExistingTransports(%1)") 00169 .arg(sourceid)); 00170 00171 ok = sigmonScanner->ScanExistingTransports(sourceid, do_follow_nit); 00172 if (ok) 00173 { 00174 scanMonitor->ScanPercentComplete(0); 00175 } 00176 else 00177 { 00178 InformUser(QObject::tr("Error tuning to transport")); 00179 Teardown(); 00180 } 00181 } 00182 else if ((ScanTypeSetting::DVBUtilsImport == scantype) && channels.size()) 00183 { 00184 ok = true; 00185 00186 LOG(VB_CHANSCAN, LOG_INFO, LOC + 00187 QString("ScanForChannels(%1)").arg(sourceid)); 00188 00189 QString card_type = CardUtil::GetRawCardType(cardid); 00190 QString sub_type = card_type; 00191 if (card_type == "DVB") 00192 { 00193 QString device = CardUtil::GetVideoDevice(cardid); 00194 00195 ok = !device.isEmpty(); 00196 if (ok) 00197 sub_type = CardUtil::ProbeDVBType(device).toUpper(); 00198 } 00199 00200 if (ok) 00201 { 00202 ok = sigmonScanner->ScanForChannels(sourceid, freq_std, 00203 sub_type, channels); 00204 } 00205 if (ok) 00206 { 00207 scanMonitor->ScanPercentComplete(0); 00208 } 00209 else 00210 { 00211 InformUser(QObject::tr("Error tuning to transport")); 00212 Teardown(); 00213 } 00214 } 00215 else if (ScanTypeSetting::TransportScan == scantype) 00216 { 00217 LOG(VB_CHANSCAN, LOG_INFO, LOC + 00218 QString("ScanTransport(%1)").arg(mplexid)); 00219 00220 ok = sigmonScanner->ScanTransport(mplexid, do_follow_nit); 00221 } 00222 else if (ScanTypeSetting::CurrentTransportScan == scantype) 00223 { 00224 QString sistandard = "mpeg"; 00225 LOG(VB_CHANSCAN, LOG_INFO, LOC + 00226 "ScanCurrentTransport(" + sistandard + ")"); 00227 ok = sigmonScanner->ScanCurrentTransport(sistandard); 00228 } 00229 00230 if (!ok) 00231 { 00232 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to handle tune complete."); 00233 InformUser(QObject::tr("Programmer Error: " 00234 "Failed to handle tune complete.")); 00235 } 00236 } 00237 00238 DTVConfParser::return_t ChannelScanner::ImportDVBUtils( 00239 uint sourceid, int cardtype, const QString &file) 00240 { 00241 channels.clear(); 00242 00243 DTVConfParser::cardtype_t type = DTVConfParser::UNKNOWN; 00244 type = (CardUtil::DVBT == cardtype) ? DTVConfParser::OFDM : type; 00245 type = (CardUtil::QPSK == cardtype) ? DTVConfParser::QPSK : type; 00246 type = (CardUtil::DVBC == cardtype) ? DTVConfParser::QAM : type; 00247 type = (CardUtil::DVBS2 == cardtype) ? DTVConfParser::DVBS2 : type; 00248 type = ((CardUtil::ATSC == cardtype) || 00249 (CardUtil::HDHOMERUN == cardtype)) ? DTVConfParser::ATSC : type; 00250 00251 DTVConfParser::return_t ret = DTVConfParser::OK; 00252 if (type == DTVConfParser::UNKNOWN) 00253 ret = DTVConfParser::ERROR_CARDTYPE; 00254 else 00255 { 00256 DTVConfParser parser(type, sourceid, file); 00257 00258 ret = parser.Parse(); 00259 if (DTVConfParser::OK == ret) 00260 channels = parser.GetChannels(); 00261 } 00262 00263 if (DTVConfParser::OK != ret) 00264 { 00265 QString msg = (DTVConfParser::ERROR_PARSE == ret) ? 00266 QObject::tr("Failed to parse '%1'") : 00267 ((DTVConfParser::ERROR_CARDTYPE == ret) ? 00268 QString("Programmer Error : incorrect card type") : 00269 QObject::tr("Failed to open '%1'")); 00270 00271 InformUser(msg); 00272 } 00273 00274 return ret; 00275 } 00276 00277 bool ChannelScanner::ImportM3U( 00278 uint cardid, const QString &inputname, uint sourceid) 00279 { 00280 (void) cardid; 00281 (void) inputname; 00282 (void) sourceid; 00283 bool ok = false; 00284 00285 #ifdef USING_IPTV 00286 // Create an IPTV scan object 00287 freeboxScanner = new IPTVChannelFetcher( 00288 cardid, inputname, sourceid, scanMonitor); 00289 00290 MonitorProgress(false, false, false, false); 00291 00292 ok = freeboxScanner->Scan(); 00293 #endif // USING_IPTV 00294 00295 if (!ok) 00296 InformUser(QObject::tr("Error starting scan")); 00297 00298 return ok; 00299 } 00300 00301 void ChannelScanner::PreScanCommon( 00302 int scantype, 00303 uint cardid, 00304 const QString &inputname, 00305 uint sourceid, 00306 bool do_ignore_signal_timeout, 00307 bool do_test_decryption) 00308 { 00309 uint signal_timeout = 1000; 00310 uint channel_timeout = 40000; 00311 CardUtil::GetTimeouts(cardid, signal_timeout, channel_timeout); 00312 00313 QString device = CardUtil::GetVideoDevice(cardid); 00314 if (device.isEmpty()) 00315 { 00316 LOG(VB_GENERAL, LOG_ERR, LOC + "No Device"); 00317 InformUser(QObject::tr("Programmer Error: No Device")); 00318 return; 00319 } 00320 00321 if (!scanMonitor) 00322 scanMonitor = new ScanMonitor(this); 00323 00324 QString card_type = CardUtil::GetRawCardType(cardid); 00325 00326 if ("DVB" == card_type) 00327 { 00328 QString sub_type = CardUtil::ProbeDVBType(device).toUpper(); 00329 bool need_nit = (("QAM" == sub_type) || 00330 ("QPSK" == sub_type) || 00331 ("OFDM" == sub_type)); 00332 00333 // Ugh, Some DVB drivers don't fully support signal monitoring... 00334 if ((ScanTypeSetting::TransportScan == scantype) || 00335 (ScanTypeSetting::FullTransportScan == scantype)) 00336 { 00337 signal_timeout = (do_ignore_signal_timeout) ? 00338 channel_timeout * 10 : signal_timeout; 00339 } 00340 00341 // ensure a minimal signal timeout of 1 second 00342 signal_timeout = max(signal_timeout, 1000U); 00343 00344 // Make sure that channel_timeout is at least 7 seconds to catch 00345 // at least one SDT section. kDVBTableTimeout in ChannelScanSM 00346 // ensures that we catch the NIT then. 00347 channel_timeout = max(channel_timeout, need_nit * 7 * 1000U); 00348 } 00349 00350 #ifdef USING_DVB 00351 if ("DVB" == card_type) 00352 channel = new DVBChannel(device); 00353 #endif 00354 00355 #ifdef USING_V4L2 00356 if (("V4L" == card_type) || ("MPEG" == card_type)) 00357 channel = new V4LChannel(NULL, device); 00358 #endif 00359 00360 #ifdef USING_HDHOMERUN 00361 if ("HDHOMERUN" == card_type) 00362 { 00363 channel = new HDHRChannel(NULL, device); 00364 } 00365 #endif // USING_HDHOMERUN 00366 00367 #ifdef USING_ASI 00368 if ("ASI" == card_type) 00369 { 00370 channel = new ASIChannel(NULL, device); 00371 } 00372 #endif // USING_ASI 00373 00374 if (!channel) 00375 { 00376 LOG(VB_GENERAL, LOG_ERR, LOC + "Channel not created"); 00377 InformUser(QObject::tr("Programmer Error: Channel not created")); 00378 return; 00379 } 00380 00381 // explicitly set the cardid 00382 channel->SetCardID(cardid); 00383 00384 // If the backend is running this may fail... 00385 if (!channel->Open()) 00386 { 00387 LOG(VB_GENERAL, LOG_ERR, LOC + "Channel could not be opened"); 00388 InformUser(QObject::tr("Channel could not be opened.")); 00389 return; 00390 } 00391 00392 ScanMonitor *lis = scanMonitor; 00393 00394 sigmonScanner = new ChannelScanSM( 00395 lis, card_type, channel, sourceid, 00396 signal_timeout, channel_timeout, inputname, 00397 do_test_decryption); 00398 00399 // If we know the channel types we can give the signal montior a hint. 00400 // Since we unfortunately do not record this info in the DB, we cannot 00401 // do this for the other scan types and have to guess later on... 00402 switch (scantype) 00403 { 00404 case ScanTypeSetting::FullScan_ATSC: 00405 sigmonScanner->SetScanDTVTunerType(DTVTunerType::kTunerTypeATSC); 00406 break; 00407 case ScanTypeSetting::FullScan_DVBC: 00408 sigmonScanner->SetScanDTVTunerType(DTVTunerType::kTunerTypeDVBC); 00409 break; 00410 case ScanTypeSetting::FullScan_DVBT: 00411 sigmonScanner->SetScanDTVTunerType(DTVTunerType::kTunerTypeDVBT); 00412 break; 00413 case ScanTypeSetting::NITAddScan_DVBT: 00414 sigmonScanner->SetScanDTVTunerType(DTVTunerType::kTunerTypeDVBT); 00415 break; 00416 case ScanTypeSetting::NITAddScan_DVBS: 00417 sigmonScanner->SetScanDTVTunerType(DTVTunerType::kTunerTypeDVBS1); 00418 break; 00419 case ScanTypeSetting::NITAddScan_DVBS2: 00420 sigmonScanner->SetScanDTVTunerType(DTVTunerType::kTunerTypeDVBS2); 00421 break; 00422 case ScanTypeSetting::NITAddScan_DVBC: 00423 sigmonScanner->SetScanDTVTunerType(DTVTunerType::kTunerTypeDVBC); 00424 break; 00425 default: 00426 break; 00427 } 00428 00429 // Signal Meters are connected here 00430 SignalMonitor *mon = sigmonScanner->GetSignalMonitor(); 00431 if (mon) 00432 mon->AddListener(lis); 00433 00434 DVBSignalMonitor *dvbm = NULL; 00435 bool using_rotor = false; 00436 00437 #ifdef USING_DVB 00438 dvbm = sigmonScanner->GetDVBSignalMonitor(); 00439 if (dvbm && mon) 00440 using_rotor = mon->HasFlags(SignalMonitor::kDVBSigMon_WaitForPos); 00441 #endif // USING_DVB 00442 00443 MonitorProgress(mon, mon, dvbm, using_rotor); 00444 }
1.7.6.1