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"