File indexing completed on 2024-05-12 04:52:11
0001 /* 0002 * dvbdevice.cpp 0003 * 0004 * Copyright (C) 2007-2011 Christoph Pfister <christophpfister@gmail.com> 0005 * 0006 * This program is free software; you can redistribute it and/or modify 0007 * it under the terms of the GNU General Public License as published by 0008 * the Free Software Foundation; either version 2 of the License, or 0009 * (at your option) any later version. 0010 * 0011 * This program is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License along 0017 * with this program; if not, write to the Free Software Foundation, Inc., 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 0019 */ 0020 0021 #include "../log.h" 0022 0023 #include <QCoreApplication> 0024 #include <QDir> 0025 0026 #if QT_VERSION >= 0x050a00 0027 # include <QRandomGenerator> 0028 #endif 0029 #include <unistd.h> 0030 0031 #include <cmath> 0032 0033 #include "dvbconfig.h" 0034 #include "dvbdevice.h" 0035 #include "dvbdevice_p.h" 0036 #include "dvbmanager.h" 0037 #include "dvbsi.h" 0038 0039 class DvbFilterInternal 0040 { 0041 public: 0042 DvbFilterInternal() : activeFilters(0) { } 0043 ~DvbFilterInternal() { } 0044 0045 QList<DvbPidFilter *> filters; 0046 int activeFilters; 0047 }; 0048 0049 class DvbSectionFilterInternal : public DvbPidFilter 0050 { 0051 public: 0052 DvbSectionFilterInternal() : activeSectionFilters(0), continuityCounter(0), 0053 wrongCrcIndex(0), bufferValid(false) 0054 { 0055 memset(wrongCrcs, 0, sizeof(wrongCrcs)); 0056 } 0057 0058 ~DvbSectionFilterInternal() { } 0059 0060 QList<DvbSectionFilter *> sectionFilters; 0061 int activeSectionFilters; 0062 0063 private: 0064 void processData(const char [188]) override; 0065 void processSections(bool force); 0066 0067 unsigned char continuityCounter; 0068 unsigned char wrongCrcIndex; 0069 bool bufferValid; 0070 QByteArray buffer; 0071 int wrongCrcs[8]; 0072 }; 0073 0074 // FIXME some debug messages may be printed too often 0075 0076 void DvbSectionFilterInternal::processData(const char data[188]) 0077 { 0078 if ((data[3] & 0x10) == 0) { 0079 // no payload 0080 qCDebug(logDvb, "MPEG-TS session doesn't have a payload"); 0081 return; 0082 } 0083 0084 unsigned char continuity = (data[3] & 0x0f); 0085 0086 if (bufferValid) { 0087 if (continuity == continuityCounter) { 0088 qCDebug(logDvb, "Section duplication: received %d, expecting %d", continuity, continuityCounter + 1); 0089 return; 0090 } 0091 0092 if (continuity != ((continuityCounter + 1) & 0x0f)) { 0093 qCDebug(logDvb, "Section discontinuity: received %d, expecting %d", continuity, continuityCounter + 1); 0094 bufferValid = false; 0095 } 0096 } 0097 0098 continuityCounter = continuity; 0099 0100 bool sectionStart = ((data[1] & 0x40) != 0); 0101 const char *payload; 0102 int payloadLength; 0103 0104 if ((data[3] & 0x20) == 0) { 0105 // adaptation field not present 0106 payload = (data + 4); 0107 payloadLength = (188 - 4); 0108 } else { 0109 // adaptation field present 0110 unsigned char length = data[4]; 0111 0112 if (length > 182) { 0113 qCDebug(logDvb, "Received a section without payload or corrupted"); 0114 return; 0115 } 0116 0117 payload = (data + 5 + length); 0118 payloadLength = (188 - 5 - length); 0119 } 0120 0121 // be careful that playloadLength is > 0 at this point 0122 0123 if (sectionStart) { 0124 int pointer = quint8(payload[0]); 0125 0126 if (pointer >= payloadLength) { 0127 qCDebug(logDvb, "Section with invalid payload pointer"); 0128 pointer = (payloadLength - 1); 0129 } 0130 0131 if (bufferValid) { 0132 buffer.append(payload + 1, pointer); 0133 processSections(true); 0134 } else { 0135 bufferValid = true; 0136 } 0137 0138 payload += (pointer + 1); 0139 payloadLength -= (pointer + 1); 0140 } 0141 0142 buffer.append(payload, payloadLength); 0143 processSections(false); 0144 } 0145 0146 void DvbSectionFilterInternal::processSections(bool force) 0147 { 0148 const char *it = buffer.constBegin(); 0149 const char *end = buffer.constEnd(); 0150 0151 while (it != end) { 0152 if (static_cast<unsigned char>(it[0]) == 0xff) { 0153 // table id == 0xff means padding 0154 it = end; 0155 break; 0156 } 0157 0158 if ((end - it) < 3) { 0159 if (force) { 0160 qCDebug(logDvb, "Section with stray data"); 0161 it = end; 0162 } 0163 0164 break; 0165 } 0166 0167 const char *sectionEnd = (it + (((static_cast<unsigned char>(it[1]) & 0x0f) << 8) | 0168 static_cast<unsigned char>(it[2])) + 3); 0169 0170 if (force && (sectionEnd > end)) { 0171 qCDebug(logDvb, "Short section"); 0172 sectionEnd = end; 0173 } 0174 0175 if (sectionEnd <= end) { 0176 int size = int(sectionEnd - it); 0177 int crc = DvbStandardSection::verifyCrc32(it, size); 0178 bool crcOk; 0179 0180 if (crc == 0) { 0181 crcOk = true; 0182 } else { 0183 for (int i = 0;; ++i) { 0184 if (i == (sizeof(wrongCrcs) / sizeof(wrongCrcs[0]))) { 0185 crcOk = false; 0186 wrongCrcs[wrongCrcIndex] = crc; 0187 0188 if ((++wrongCrcIndex) == i) { 0189 wrongCrcIndex = 0; 0190 } 0191 0192 break; 0193 } 0194 0195 if (wrongCrcs[i] == crc) { 0196 crcOk = true; 0197 break; 0198 } 0199 } 0200 } 0201 0202 if (crcOk) { 0203 for (int i = 0; i < sectionFilters.size(); ++i) { 0204 sectionFilters.at(i)->processSection(it, size); 0205 } 0206 } 0207 0208 it = sectionEnd; 0209 continue; 0210 } 0211 0212 break; 0213 } 0214 0215 buffer.remove(0, int(it - buffer.constBegin())); 0216 } 0217 0218 class DvbDataDumper : public QFile, public DvbPidFilter 0219 { 0220 public: 0221 DvbDataDumper(); 0222 ~DvbDataDumper(); 0223 0224 void processData(const char [188]) override; 0225 }; 0226 0227 DvbDataDumper::DvbDataDumper() 0228 { 0229 #if QT_VERSION >= 0x050a00 0230 quint32 rand = QRandomGenerator::global()->generate(); 0231 #else 0232 quint32 rand = qrand(); 0233 #endif 0234 0235 setFileName(QDir::homePath() + QLatin1String("/KaffeineDvbDump-") + QString::number(rand, 16) + 0236 QLatin1String(".bin")); 0237 0238 if (!open(QIODevice::WriteOnly | QIODevice::Truncate)) { 0239 qCWarning(logDev, "Can't open %s", qPrintable(fileName())); 0240 } 0241 } 0242 0243 DvbDataDumper::~DvbDataDumper() 0244 { 0245 } 0246 0247 void DvbDataDumper::processData(const char data[188]) 0248 { 0249 write(data, 188); 0250 } 0251 0252 DvbDevice::DvbDevice(DvbBackendDevice *backend_, QObject *parent) : QObject(parent), 0253 backend(backend_), deviceState(DeviceReleased), dataDumper(NULL), cleanUpFilters(false), 0254 isAuto(false), unusedBuffersHead(NULL), usedBuffersHead(NULL), usedBuffersTail(NULL) 0255 { 0256 backend->setFrontendDevice(this); 0257 backend->setDeviceEnabled(true); // FIXME 0258 0259 connect(&frontendTimer, SIGNAL(timeout()), this, SLOT(frontendEvent())); 0260 } 0261 0262 DvbDevice::~DvbDevice() 0263 { 0264 backend->release(); 0265 0266 for (DvbDeviceDataBuffer *buffer = unusedBuffersHead; buffer != NULL;) { 0267 DvbDeviceDataBuffer *nextBuffer = buffer->next; 0268 delete buffer; 0269 buffer = nextBuffer; 0270 } 0271 0272 for (DvbDeviceDataBuffer *buffer = usedBuffersHead; buffer != NULL;) { 0273 DvbDeviceDataBuffer *nextBuffer = buffer->next; 0274 delete buffer; 0275 buffer = nextBuffer; 0276 } 0277 } 0278 0279 DvbDevice::TransmissionTypes DvbDevice::getTransmissionTypes() const 0280 { 0281 return backend->getTransmissionTypes(); 0282 } 0283 0284 QString DvbDevice::getDeviceId() const 0285 { 0286 return backend->getDeviceId(); 0287 } 0288 0289 QString DvbDevice::getFrontendName() const 0290 { 0291 return backend->getFrontendName(); 0292 } 0293 0294 void DvbDevice::tune(const DvbTransponder &transponder) 0295 { 0296 DvbTransponderBase::TransmissionType transmissionType = transponder.getTransmissionType(); 0297 0298 autoTransponder.setTransmissionType(transmissionType); 0299 0300 if ((transmissionType != DvbTransponderBase::DvbS) && 0301 (transmissionType != DvbTransponderBase::DvbS2)) { 0302 if (backend->tune(transponder)) { 0303 setDeviceState(DeviceTuning); 0304 frontendTimeout = config->timeout; 0305 frontendTimer.start(100); 0306 discardBuffers(); 0307 } else { 0308 setDeviceState(DeviceTuning); 0309 autoTransponder.setTransmissionType(DvbTransponderBase::Invalid); 0310 setDeviceState(DeviceIdle); 0311 } 0312 0313 return; 0314 } 0315 0316 bool moveRotor = false; 0317 DvbTransponder intermediate = transponder; 0318 0319 // DVB LNBf IF and DiSeqC switch settings 0320 0321 int satNumber = -1; // No DiseqC Switch 0322 0323 if (config->configuration == DvbConfigBase::DiseqcSwitch) 0324 satNumber = config->lnbNumber; 0325 0326 // FIXME: add support for SCR/Unicable 0327 if (!backend->satSetup(config->currentLnb.alias, satNumber, 0)) 0328 return; 0329 0330 backend->setHighVoltage(config->higherVoltage); 0331 0332 // rotor 0333 0334 switch (config->configuration) { 0335 case DvbConfigBase::DiseqcSwitch: 0336 case DvbConfigBase::NoDiseqc: 0337 // Everything was already prepared via satSetup(). 0338 break; 0339 0340 case DvbConfigBase::UsalsRotor: { 0341 QString source = config->scanSource; 0342 source.remove(0, source.lastIndexOf(QLatin1Char('-')) + 1); 0343 0344 bool ok = false; 0345 double orbitalPosition = 0; 0346 0347 if (source.endsWith(QLatin1Char('E'))) { 0348 source.chop(1); 0349 orbitalPosition = source.toDouble(&ok); 0350 } else if (source.endsWith(QLatin1Char('W'))) { 0351 source.chop(1); 0352 orbitalPosition = (-source.toDouble(&ok)); 0353 } 0354 0355 if (!ok) 0356 qCWarning(logDev, "Can't extract orbital position from %s", qPrintable(config->scanSource)); 0357 0358 double radius = 6378; 0359 double semiMajorAxis = 42164; 0360 double temp = (radius * cos(config->latitude * M_PI / 180)); 0361 double temp2 = ((orbitalPosition - config->longitude) * M_PI / 180); 0362 double angle = (temp2 + atan(sin(temp2) / ((semiMajorAxis / temp) - cos(temp2)))); 0363 int value = 0; 0364 0365 if (angle >= 0) { 0366 // east 0367 value = int((16 * angle * 180 / M_PI) + 0.5); 0368 value |= 0xe000; 0369 } else { 0370 // west 0371 value = int((16 * (-angle) * 180 / M_PI) + 0.5); 0372 value |= 0xd000; 0373 } 0374 0375 char cmd[] = { char(0xe0), 0x31, 0x6e, char(value / 256), char(value % 256) }; 0376 usleep(15000); 0377 backend->sendMessage(cmd, sizeof(cmd)); 0378 usleep(15000); 0379 moveRotor = true; 0380 break; 0381 } 0382 0383 case DvbConfigBase::PositionsRotor: { 0384 char cmd[] = { char(0xe0), 0x31, 0x6b, char(config->lnbNumber) }; 0385 usleep(15000); 0386 backend->sendMessage(cmd, sizeof(cmd)); 0387 usleep(15000); 0388 moveRotor = true; 0389 break; 0390 } 0391 } 0392 0393 // tune 0394 0395 if (backend->tune(intermediate)) { 0396 if (!moveRotor) { 0397 setDeviceState(DeviceTuning); 0398 frontendTimeout = config->timeout; 0399 } else { 0400 setDeviceState(DeviceRotorMoving); 0401 frontendTimeout = 15000; 0402 } 0403 0404 frontendTimer.start(100); 0405 discardBuffers(); 0406 } else { 0407 setDeviceState(DeviceTuning); 0408 autoTransponder.setTransmissionType(DvbTransponderBase::Invalid); 0409 setDeviceState(DeviceIdle); 0410 } 0411 } 0412 0413 void DvbDevice::autoTune(const DvbTransponder &transponder) 0414 { 0415 DvbTransponderBase::TransmissionType transmissionType = transponder.getTransmissionType(); 0416 0417 autoTransponder = transponder; 0418 0419 if (transmissionType == DvbTransponderBase::DvbT) { 0420 DvbTTransponder *autoTTransponder = autoTransponder.as<DvbTTransponder>(); 0421 capabilities = backend->getCapabilities(); 0422 0423 // we have to iterate over unsupported AUTO values 0424 0425 if ((capabilities & DvbTFecAuto) == 0) { 0426 autoTTransponder->fecRateHigh = DvbTTransponder::Fec2_3; 0427 } 0428 0429 if ((capabilities & DvbTGuardIntervalAuto) == 0) { 0430 autoTTransponder->guardInterval = DvbTTransponder::GuardInterval1_8; 0431 } 0432 0433 if ((capabilities & DvbTModulationAuto) == 0) { 0434 autoTTransponder->modulation = DvbTTransponder::Qam64; 0435 } 0436 0437 if ((capabilities & DvbTTransmissionModeAuto) == 0) { 0438 autoTTransponder->transmissionMode = DvbTTransponder::TransmissionMode8k; 0439 } 0440 isAuto = true; 0441 tune(autoTransponder); 0442 } else if (transmissionType == DvbTransponderBase::DvbT2) { 0443 // I guess all DVB-T2 devices support auto-detection 0444 isAuto = true; 0445 tune(autoTransponder); 0446 } else if (transmissionType == DvbTransponderBase::IsdbT) { 0447 // ISDB-T Currently, all ISDB-T tuners should support auto mode 0448 isAuto = true; 0449 tune(autoTransponder); 0450 } else { 0451 qCWarning(logDev, "Can't do auto-tune for %d", transmissionType); 0452 return; 0453 } 0454 0455 isAuto = true; 0456 tune(autoTransponder); 0457 } 0458 0459 bool DvbDevice::addPidFilter(int pid, DvbPidFilter *filter) 0460 { 0461 QMap<int, DvbFilterInternal>::iterator it = filters.find(pid); 0462 0463 if (it == filters.end()) { 0464 it = filters.insert(pid, DvbFilterInternal()); 0465 0466 if (dataDumper != NULL) { 0467 it->filters.append(dataDumper); 0468 } 0469 } 0470 0471 if (it->activeFilters == 0) { 0472 if (!backend->addPidFilter(pid)) { 0473 cleanUpFilters = true; 0474 return false; 0475 } 0476 } 0477 0478 if (it->filters.contains(filter)) { 0479 qCInfo(logDev, "Using the same filter for the same pid more than once"); 0480 return true; 0481 } 0482 0483 it->filters.append(filter); 0484 ++it->activeFilters; 0485 return true; 0486 } 0487 0488 bool DvbDevice::addSectionFilter(int pid, DvbSectionFilter *filter) 0489 { 0490 QMap<int, DvbSectionFilterInternal>::iterator it = sectionFilters.find(pid); 0491 0492 if (it == sectionFilters.end()) { 0493 it = sectionFilters.insert(pid, DvbSectionFilterInternal()); 0494 } 0495 0496 if (it->activeSectionFilters == 0) { 0497 if (!addPidFilter(pid, &(*it))) { 0498 cleanUpFilters = true; 0499 return false; 0500 } 0501 } 0502 0503 if (it->sectionFilters.contains(filter)) { 0504 qCInfo(logDev, "Using the same filter for the same pid more than once"); 0505 return true; 0506 } 0507 0508 it->sectionFilters.append(filter); 0509 ++it->activeSectionFilters; 0510 return true; 0511 } 0512 0513 void DvbDevice::removePidFilter(int pid, DvbPidFilter *filter) 0514 { 0515 QMap<int, DvbFilterInternal>::iterator it = filters.find(pid); 0516 int index; 0517 0518 if (it != filters.end()) { 0519 index = it->filters.indexOf(filter); 0520 } else { 0521 index = -1; 0522 } 0523 0524 if (index < 0) { 0525 qCWarning(logDev, "Trying to remove a nonexistent filter"); 0526 return; 0527 } 0528 0529 it->filters.replace(index, &dummyPidFilter); 0530 --it->activeFilters; 0531 0532 if (it->activeFilters == 0) { 0533 backend->removePidFilter(pid); 0534 } 0535 0536 cleanUpFilters = true; 0537 } 0538 0539 void DvbDevice::removeSectionFilter(int pid, DvbSectionFilter *filter) 0540 { 0541 QMap<int, DvbSectionFilterInternal>::iterator it = sectionFilters.find(pid); 0542 int index; 0543 0544 if (it != sectionFilters.end()) { 0545 index = it->sectionFilters.indexOf(filter); 0546 } else { 0547 index = -1; 0548 } 0549 0550 if (index < 0) { 0551 qCWarning(logDev, "Trying to remove a nonexistent filter"); 0552 return; 0553 } 0554 0555 it->sectionFilters.replace(index, &dummySectionFilter); 0556 --it->activeSectionFilters; 0557 0558 if (it->activeSectionFilters == 0) { 0559 removePidFilter(pid, &(*it)); 0560 } 0561 0562 cleanUpFilters = true; 0563 } 0564 0565 void DvbDevice::startDescrambling(const QByteArray &pmtSectionData, QObject *user) 0566 { 0567 DvbPmtSection pmtSection(pmtSectionData); 0568 0569 if (!pmtSection.isValid()) { 0570 qCWarning(logDev, "PMT section is invalid"); 0571 } 0572 0573 int serviceId = pmtSection.programNumber(); 0574 0575 if (!descramblingServices.contains(serviceId)) { 0576 backend->startDescrambling(pmtSectionData); 0577 } 0578 0579 if (!descramblingServices.contains(serviceId, user)) { 0580 descramblingServices.insert(serviceId, user); 0581 } 0582 } 0583 0584 void DvbDevice::stopDescrambling(const QByteArray &pmtSectionData, QObject *user) 0585 { 0586 DvbPmtSection pmtSection(pmtSectionData); 0587 0588 if (!pmtSection.isValid()) { 0589 qCWarning(logDev, "PMT section is invalid"); 0590 } 0591 0592 int serviceId = pmtSection.programNumber(); 0593 0594 if (!descramblingServices.contains(serviceId, user)) { 0595 qCInfo(logDev, "Service has not been started while stop descrambling"); 0596 return; 0597 } 0598 0599 descramblingServices.remove(serviceId, user); 0600 0601 if (!descramblingServices.contains(serviceId)) { 0602 backend->stopDescrambling(serviceId); 0603 } 0604 } 0605 0606 bool DvbDevice::isTuned() const 0607 { 0608 return backend->isTuned(); 0609 } 0610 0611 bool DvbDevice::getProps(DvbTransponder &transponder) const 0612 { 0613 return backend->getProps(transponder); 0614 } 0615 0616 float DvbDevice::getSignal(DvbBackendDevice::Scale &scale) const 0617 { 0618 return backend->getSignal(scale); 0619 } 0620 0621 float DvbDevice::getSnr(DvbBackendDevice::Scale &scale) const 0622 { 0623 return backend->getSnr(scale); 0624 } 0625 0626 DvbTransponder DvbDevice::getAutoTransponder() const 0627 { 0628 // FIXME query back information like frequency - tuning parameters - ... 0629 return autoTransponder; 0630 } 0631 0632 bool DvbDevice::acquire(const DvbConfigBase *config_) 0633 { 0634 Q_ASSERT(deviceState == DeviceReleased); 0635 0636 if (backend->acquire()) { 0637 config = config_; 0638 autoTransponder.setTransmissionType(DvbTransponderBase::Invalid); 0639 setDeviceState(DeviceIdle); 0640 return true; 0641 } 0642 0643 return false; 0644 } 0645 0646 void DvbDevice::reacquire(const DvbConfigBase *config_) 0647 { 0648 Q_ASSERT(deviceState != DeviceReleased); 0649 setDeviceState(DeviceReleased); 0650 stop(); 0651 config = config_; 0652 autoTransponder.setTransmissionType(DvbTransponderBase::Invalid); 0653 setDeviceState(DeviceIdle); 0654 } 0655 0656 void DvbDevice::release() 0657 { 0658 setDeviceState(DeviceReleased); 0659 stop(); 0660 backend->release(); 0661 } 0662 0663 void DvbDevice::enableDvbDump() 0664 { 0665 if (dataDumper != NULL) { 0666 return; 0667 } 0668 0669 dataDumper = new DvbDataDumper(); 0670 0671 QMap<int, DvbFilterInternal>::iterator it = filters.begin(); 0672 QMap<int, DvbFilterInternal>::iterator end = filters.end(); 0673 0674 for (; it != end; ++it) { 0675 it->filters.append(dataDumper); 0676 } 0677 0678 backend->enableDvbDump(); 0679 } 0680 0681 void DvbDevice::frontendEvent() 0682 { 0683 DvbTransponderBase::TransmissionType transmissionType = autoTransponder.getTransmissionType(); 0684 0685 if (backend->isTuned()) { 0686 qCDebug(logDvb, "tuning succeeded on %.2f MHz", backend->getFrqMHz()); 0687 frontendTimer.stop(); 0688 backend->getProps(autoTransponder); 0689 setDeviceState(DeviceTuned); 0690 return; 0691 } 0692 0693 // FIXME progress bar when moving rotor 0694 0695 frontendTimeout -= 100; 0696 0697 if (frontendTimeout <= 0) { 0698 frontendTimer.stop(); 0699 0700 if (!isAuto) { 0701 qCDebug(logDvb, "tuning failed on %.2f MHz", backend->getFrqMHz()); 0702 autoTransponder.setTransmissionType(DvbTransponderBase::Invalid); 0703 setDeviceState(DeviceIdle); 0704 return; 0705 } 0706 0707 bool carry = true; 0708 0709 /* 0710 * As ISDB-T always support auto-scan, we only need to simulate 0711 * it for DVB-T 0712 */ 0713 if (transmissionType == DvbTransponderBase::DvbT) { 0714 DvbBackendDevice::Scale scale; 0715 0716 DvbTTransponder *autoTTransponder = autoTransponder.as<DvbTTransponder>(); 0717 float signal = backend->getSignal(scale); 0718 0719 if ((scale != DvbBackendDevice::NotSupported) && (signal < 15)) { 0720 // signal too weak 0721 qCInfo(logDev, "Signal too weak on %.2f MHz", backend->getFrqMHz()); 0722 /* 0723 * FIXME: ignoring a too weak signal is not so easy, 0724 * as it depends on the scale, and scale is broken on 0725 * several drivers. Also, signal itself is not a good 0726 * indicator of the quality. Better to just print a 0727 * warning, and not fail. 0728 */ 0729 #if 0 0730 autoTransponder.setTransmissionType(DvbTransponderBase::Invalid); 0731 setDeviceState(DeviceIdle); 0732 return; 0733 #endif 0734 } 0735 0736 if (carry && ((capabilities & DvbTFecAuto) == 0)) { 0737 switch (autoTTransponder->fecRateHigh) { 0738 case DvbTTransponder::Fec2_3: 0739 autoTTransponder->fecRateHigh = DvbTTransponder::Fec3_4; 0740 carry = false; 0741 break; 0742 case DvbTTransponder::Fec3_4: 0743 autoTTransponder->fecRateHigh = DvbTTransponder::Fec1_2; 0744 carry = false; 0745 break; 0746 case DvbTTransponder::Fec1_2: 0747 autoTTransponder->fecRateHigh = DvbTTransponder::Fec5_6; 0748 carry = false; 0749 break; 0750 case DvbTTransponder::Fec5_6: 0751 autoTTransponder->fecRateHigh = DvbTTransponder::Fec7_8; 0752 carry = false; 0753 break; 0754 default: 0755 autoTTransponder->fecRateHigh = DvbTTransponder::Fec2_3; 0756 break; 0757 } 0758 } 0759 0760 if (carry && ((capabilities & DvbTGuardIntervalAuto) == 0)) { 0761 switch (autoTTransponder->guardInterval) { 0762 case DvbTTransponder::GuardInterval1_8: 0763 autoTTransponder->guardInterval = 0764 DvbTTransponder::GuardInterval1_32; 0765 carry = false; 0766 break; 0767 case DvbTTransponder::GuardInterval1_32: 0768 autoTTransponder->guardInterval = 0769 DvbTTransponder::GuardInterval1_4; 0770 carry = false; 0771 break; 0772 case DvbTTransponder::GuardInterval1_4: 0773 autoTTransponder->guardInterval = 0774 DvbTTransponder::GuardInterval1_16; 0775 carry = false; 0776 break; 0777 case DvbTTransponder::GuardInterval1_16: 0778 case DvbTTransponder::GuardIntervalAuto: 0779 autoTTransponder->guardInterval = 0780 DvbTTransponder::GuardInterval1_8; 0781 break; 0782 } 0783 } 0784 0785 if (carry && ((capabilities & DvbTModulationAuto) == 0)) { 0786 switch (autoTTransponder->modulation) { 0787 case DvbTTransponder::Qam64: 0788 autoTTransponder->modulation = DvbTTransponder::Qam16; 0789 carry = false; 0790 break; 0791 case DvbTTransponder::Qam16: 0792 autoTTransponder->modulation = DvbTTransponder::Qpsk; 0793 carry = false; 0794 break; 0795 case DvbTTransponder::Qpsk: 0796 case DvbTTransponder::ModulationAuto: 0797 autoTTransponder->modulation = DvbTTransponder::Qam64; 0798 break; 0799 } 0800 } 0801 0802 if (carry && ((capabilities & DvbTTransmissionModeAuto) == 0)) { 0803 switch (autoTTransponder->transmissionMode) { 0804 case DvbTTransponder::TransmissionMode8k: 0805 autoTTransponder->transmissionMode = 0806 DvbTTransponder::TransmissionMode2k; 0807 carry = false; 0808 break; 0809 case DvbTTransponder::TransmissionMode2k: 0810 /* outcommented so that clearly no compatibility problem arises 0811 autoTTransponder->transmissionMode = 0812 DvbTTransponder::TransmissionMode4k; 0813 carry = false; 0814 break; 0815 */ 0816 case DvbTTransponder::TransmissionMode4k: 0817 case DvbTTransponder::TransmissionModeAuto: 0818 autoTTransponder->transmissionMode = 0819 DvbTTransponder::TransmissionMode8k; 0820 break; 0821 } 0822 } 0823 } 0824 0825 if (!carry) { 0826 tune(autoTransponder); 0827 } else { 0828 qCDebug(logDvb, "tuning failed on %.2f MHz", backend->getFrqMHz());; 0829 setDeviceState(DeviceIdle); 0830 } 0831 } 0832 } 0833 0834 void DvbDevice::setDeviceState(DeviceState newState) 0835 { 0836 if (deviceState != newState) { 0837 deviceState = newState; 0838 emit stateChanged(); 0839 } 0840 } 0841 0842 void DvbDevice::discardBuffers() 0843 { 0844 dataChannelMutex.lock(); 0845 0846 if (usedBuffersHead != NULL) { 0847 usedBuffersHead->size = 0; 0848 DvbDeviceDataBuffer *nextBuffer = usedBuffersHead->next; 0849 usedBuffersHead->next = NULL; 0850 0851 if (nextBuffer != NULL) { 0852 nextBuffer->next = unusedBuffersHead; 0853 unusedBuffersHead = nextBuffer; 0854 } 0855 } 0856 0857 dataChannelMutex.unlock(); 0858 } 0859 0860 void DvbDevice::stop() 0861 { 0862 isAuto = false; 0863 frontendTimer.stop(); 0864 0865 for (QMap<int, DvbFilterInternal>::ConstIterator it = filters.constBegin(); 0866 it != filters.constEnd(); ++it) { 0867 foreach (DvbPidFilter *filter, it->filters) { 0868 if ((filter != &dummyPidFilter) && (filter != dataDumper)) { 0869 int pid = it.key(); 0870 qCDebug(logDvb, "removing pending filter %d", pid); 0871 removePidFilter(pid, filter); 0872 } 0873 } 0874 } 0875 0876 for (QMap<int, DvbSectionFilterInternal>::ConstIterator it = sectionFilters.constBegin(); 0877 it != sectionFilters.constEnd(); ++it) { 0878 foreach (DvbSectionFilter *sectionFilter, it->sectionFilters) { 0879 if (sectionFilter != &dummySectionFilter) { 0880 int pid = it.key(); 0881 qCDebug(logDvb, "removing pending filter %d", pid); 0882 removeSectionFilter(pid, sectionFilter); 0883 } 0884 } 0885 } 0886 } 0887 0888 DvbDataBuffer DvbDevice::getBuffer() 0889 { 0890 dataChannelMutex.lock(); 0891 DvbDeviceDataBuffer *buffer = unusedBuffersHead; 0892 0893 if (buffer != NULL) { 0894 unusedBuffersHead = buffer->next; 0895 dataChannelMutex.unlock(); 0896 } else { 0897 dataChannelMutex.unlock(); 0898 buffer = new DvbDeviceDataBuffer; 0899 } 0900 0901 return DvbDataBuffer(buffer->data, sizeof(buffer->data)); 0902 } 0903 0904 void DvbDevice::writeBuffer(const DvbDataBuffer &dataBuffer) 0905 { 0906 DvbDeviceDataBuffer *buffer = reinterpret_cast<DvbDeviceDataBuffer *>(dataBuffer.data); 0907 Q_ASSERT(buffer->data == dataBuffer.data); 0908 0909 if (dataBuffer.dataSize > 0) { 0910 buffer->size = dataBuffer.dataSize; 0911 dataChannelMutex.lock(); 0912 bool wakeUp = false; 0913 0914 if (usedBuffersHead != NULL) { 0915 usedBuffersTail->next = buffer; 0916 } else { 0917 usedBuffersHead = buffer; 0918 wakeUp = true; 0919 } 0920 0921 usedBuffersTail = buffer; 0922 usedBuffersTail->next = NULL; 0923 dataChannelMutex.unlock(); 0924 0925 if (wakeUp) { 0926 QCoreApplication::postEvent(this, new QEvent(QEvent::User)); 0927 } 0928 } else { 0929 dataChannelMutex.lock(); 0930 buffer->next = unusedBuffersHead; 0931 unusedBuffersHead = buffer; 0932 dataChannelMutex.unlock(); 0933 } 0934 } 0935 0936 void DvbDevice::customEvent(QEvent *) 0937 { 0938 if (cleanUpFilters) { 0939 cleanUpFilters = false; 0940 0941 { 0942 QMap<int, DvbFilterInternal>::iterator it = filters.begin(); 0943 QMap<int, DvbFilterInternal>::iterator end = filters.end(); 0944 0945 while (it != end) { 0946 if (it->activeFilters == 0) { 0947 it = filters.erase(it); 0948 } else { 0949 it->filters.removeAll(&dummyPidFilter); 0950 ++it; 0951 } 0952 } 0953 } 0954 0955 { 0956 QMap<int, DvbSectionFilterInternal>::iterator it = sectionFilters.begin(); 0957 QMap<int, DvbSectionFilterInternal>::iterator end = sectionFilters.end(); 0958 0959 while (it != end) { 0960 if (it->activeSectionFilters == 0) { 0961 it = sectionFilters.erase(it); 0962 } else { 0963 it->sectionFilters.removeAll(&dummySectionFilter); 0964 ++it; 0965 } 0966 } 0967 } 0968 } 0969 0970 DvbDeviceDataBuffer *buffer = NULL; 0971 0972 while (true) { 0973 dataChannelMutex.lock(); 0974 0975 if (buffer != NULL) { 0976 usedBuffersHead = buffer->next; 0977 buffer->next = unusedBuffersHead; 0978 unusedBuffersHead = buffer; 0979 } 0980 0981 buffer = usedBuffersHead; 0982 dataChannelMutex.unlock(); 0983 0984 if (buffer == NULL) { 0985 break; 0986 } 0987 0988 for (int i = 0; i < buffer->size; i += 188) { 0989 char *packet = (buffer->data + i); 0990 0991 if ((packet[1] & 0x80) != 0) { 0992 // transport error indicator 0993 continue; 0994 } 0995 0996 int pid = ((static_cast<unsigned char>(packet[1]) << 8) | 0997 static_cast<unsigned char>(packet[2])) & ((1 << 13) - 1); 0998 0999 QMap<int, DvbFilterInternal>::const_iterator it = filters.constFind(pid); 1000 1001 if (it == filters.constEnd()) { 1002 continue; 1003 } 1004 1005 const QList<DvbPidFilter *> &pidFilters = it->filters; 1006 int pidFiltersSize = pidFilters.size(); 1007 1008 for (int j = 0; j < pidFiltersSize; ++j) { 1009 pidFilters.at(j)->processData(packet); 1010 } 1011 } 1012 } 1013 } 1014 1015 #include "moc_dvbdevice.cpp"