Files
sdrangel/plugins/channeltx/moddatv/datvmodsource.cpp
T
Jon BenistonandClaude Opus 5 109a08a50f Apply only the settings keys given in the remaining keyed applySettings
The same fix as da31464dd for the plugins whose applySettings takes the key list first, which
that sweep missed: 35 channels, modulators, sinks, sources and one MIMO device copied the
whole settings struct on every message, so a GUI message with no keys arriving just after an
API patch put the old values back. The DSD demodulator lost the deviation set at creation
this way.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 19:54:00 +01:00

894 lines
30 KiB
C++

///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 Edouard Griffiths, F4EXB //
// Copyright (C) 2021 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#define BOOST_CHRONO_HEADER_ONLY
#include <boost/chrono/chrono.hpp>
//#include <time.h>
#include <QDebug>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QBuffer>
#include <QUdpSocket>
#include <QHostAddress>
#include <QNetworkDatagram>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}
#include "util/messagequeue.h"
#include "datvmodreport.h"
#include "datvmodsource.h"
#ifdef _WIN32
#include <winsock.h>
#pragma comment(lib, "Ws2_32.lib")
#endif
const int DATVModSource::m_levelNbSamples = 10000; // every 10ms
// Get transport stream bitrate from file
int DATVModSource::getTSBitrate(const QString& filename)
{
AVFormatContext *fmtCtx = nullptr;
QByteArray ba = filename.toLocal8Bit();
const char *filenameChars = ba.data();
if (avformat_open_input(&fmtCtx, filenameChars, nullptr, nullptr) < 0)
{
qCritical() << "DATVModSource: Could not open source file " << filename;
return -1;
}
if (avformat_find_stream_info(fmtCtx, nullptr) < 0)
{
qCritical() << "DATVModSource: Could not find stream information for " << filename;
avformat_close_input(&fmtCtx);
return -1;
}
int bitrate = fmtCtx->bit_rate;
avformat_close_input(&fmtCtx);
return bitrate;
}
// Get data bitrate (i.e. excluding FEC overhead)
int DATVModSource::getDVBSDataBitrate(const DATVModSettings& settings) const
{
float fecFactor;
float plFactor;
float bitsPerSymbol;
switch (settings.m_modulation)
{
case DATVModSettings::BPSK:
bitsPerSymbol = 1.0f;
break;
case DATVModSettings::QPSK:
bitsPerSymbol = 2.0f;
break;
case DATVModSettings::PSK8:
bitsPerSymbol = 3.0f;
break;
case DATVModSettings::APSK16:
bitsPerSymbol = 4.0f;
break;
case DATVModSettings::APSK32:
bitsPerSymbol = 5.0f;
break;
}
if (settings.m_standard == DATVModSettings::DVB_S)
{
float rsFactor;
float convFactor;
rsFactor = DVBS::tsPacketLen/(float)DVBS::rsPacketLen;
switch (settings.m_fec)
{
case DATVModSettings::FEC12:
convFactor = 1.0f/2.0f;
break;
case DATVModSettings::FEC23:
convFactor = 2.0f/3.0f;
break;
case DATVModSettings::FEC34:
convFactor = 3.0f/4.0f;
break;
case DATVModSettings::FEC56:
convFactor = 5.0f/6.0f;
break;
case DATVModSettings::FEC78:
convFactor = 7.0f/8.0f;
break;
case DATVModSettings::FEC45:
convFactor = 4.0f/5.0f;
break;
case DATVModSettings::FEC89:
convFactor = 8.0f/9.0f;
break;
case DATVModSettings::FEC910:
convFactor = 9.0f/10.0f;
break;
case DATVModSettings::FEC14:
convFactor = 1.0f/4.0f;
break;
case DATVModSettings::FEC13:
convFactor = 1.0f/3.0f;
break;
case DATVModSettings::FEC25:
convFactor = 2.0f/5.0f;
break;
case DATVModSettings::FEC35:
convFactor = 3.0f/5.0f;
break;
}
fecFactor = rsFactor * convFactor;
plFactor = 1.0f;
}
else
{
// For normal frames
int codedBlockSize = 64800;
int uncodedBlockSize;
int bbHeaderBits = 80;
// See table 5a in DVBS2 spec
switch (settings.m_fec)
{
case DATVModSettings::FEC12:
uncodedBlockSize = 32208;
break;
case DATVModSettings::FEC23:
uncodedBlockSize = 43040;
break;
case DATVModSettings::FEC34:
uncodedBlockSize = 48408;
break;
case DATVModSettings::FEC56:
uncodedBlockSize = 53840;
break;
case DATVModSettings::FEC45:
uncodedBlockSize = 51648;
break;
case DATVModSettings::FEC89:
uncodedBlockSize = 57472;
break;
case DATVModSettings::FEC910:
uncodedBlockSize = 58192;
break;
case DATVModSettings::FEC14:
uncodedBlockSize = 16008;
break;
case DATVModSettings::FEC13:
uncodedBlockSize = 21408;
break;
case DATVModSettings::FEC25:
uncodedBlockSize = 25728;
break;
case DATVModSettings::FEC35:
uncodedBlockSize = 38688;
break;
default:
qDebug() << "DATVModSource::getDVBSDataBitrate: Unsupported DVB-S2 code rate";
break;
}
fecFactor = (uncodedBlockSize-bbHeaderBits)/(float)codedBlockSize;
float symbolsPerFrame = codedBlockSize/bitsPerSymbol;
// 90 symbols for PL header
plFactor = symbolsPerFrame / (symbolsPerFrame + 90.0f);
}
return std::round(settings.m_symbolRate * bitsPerSymbol * fecFactor * plFactor);
}
void DATVModSource::checkBitrates()
{
int dataBitrate = getDVBSDataBitrate(m_settings);
qDebug() << "MPEG-TS bitrate: " << m_mpegTSBitrate;
qDebug() << "DVB data bitrate: " << dataBitrate;
if (dataBitrate < m_mpegTSBitrate)
qWarning() << "DVB data bitrate is lower than the bitrate of the MPEG transport stream";
m_tsRatio = m_mpegTSBitrate/(float)dataBitrate;
}
DATVModSource::DATVModSource() :
m_mpegTSBitrate(0),
m_mpegTSSize(0),
m_sampleIdx(0),
m_frameIdx(0),
m_frameCount(0),
m_tsRatio(0.0f),
m_symbolCount(0),
m_symbolSel(0),
m_symbolIdx(0),
m_samplesPerSymbol(1),
m_udpSocket(nullptr),
m_udpByteCount(0),
m_udpAbsByteCount(0),
m_udpBufferIdx(0),
m_udpBufferCount(0),
m_udpMaxBufferUtilization(0),
m_sampleRate(0),
m_channelSampleRate(1000000),
m_channelFrequencyOffset(0),
m_tsFileOK(false),
m_messageQueueToGUI(nullptr)
{
m_interpolatorDistanceRemain = 0.0f;
m_interpolatorDistance = 1.0f;
applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true);
applySettings(QStringList(), m_settings, true);
}
DATVModSource::~DATVModSource()
{
}
void DATVModSource::pull(SampleVector::iterator begin, unsigned int nbSamples)
{
std::for_each(
begin,
begin + nbSamples,
[this](Sample& s) {
pullOne(s);
}
);
}
void DATVModSource::prefetch(unsigned int nbSamples)
{
(void) nbSamples;
}
void DATVModSource::pullOne(Sample& sample)
{
if (m_settings.m_channelMute)
{
sample.m_real = 0.0f;
sample.m_imag = 0.0f;
return;
}
Complex ci;
if (m_sampleRate == m_channelSampleRate) // no interpolation nor decimation
{
modulateSample();
pullFinalize(m_modSample, sample);
}
else
{
if (m_interpolatorDistance > 1.0f) // decimate
{
modulateSample();
while (!m_interpolator.decimate(&m_interpolatorDistanceRemain, m_modSample, &ci))
modulateSample();
}
else
{
if (m_interpolator.interpolate(&m_interpolatorDistanceRemain, m_modSample, &ci))
modulateSample();
}
m_interpolatorDistanceRemain += m_interpolatorDistance;
pullFinalize(ci, sample);
}
}
void DATVModSource::pullFinalize(Complex& ci, Sample& sample)
{
ci *= m_carrierNco.nextIQ(); // shift to carrier frequency
double magsq = ci.real() * ci.real() + ci.imag() * ci.imag();
m_movingAverage(magsq);
sample.m_real = (FixReal) (ci.real() * SDR_TX_SCALEF);
sample.m_imag = (FixReal) (ci.imag() * SDR_TX_SCALEF);
}
void DATVModSource::modulateSample()
{
Real i, q;
if (m_sampleIdx == 0)
{
while (m_symbolCount == 0)
{
bool tsFileReady = (m_settings.m_source == DATVModSettings::SourceFile)
&& m_settings.m_tsFilePlay
&& m_tsFileOK
&& !m_mpegTSStream.eof();
if (tsFileReady
&& (m_frameIdx/(m_frameCount+1.0f) < m_tsRatio) // Insert null packets if file rate is lower than DVB-S data rate
)
{
// Read transport stream packet from file
m_mpegTSStream.read((char *)m_mpegTS, sizeof(m_mpegTS));
m_frameIdx++;
m_frameCount++;
}
else if ((m_settings.m_source == DATVModSettings::SourceUDP)
&& (m_udpBufferIdx < m_udpBufferCount)
)
{
// Copy transport stream packet from UDP buffer
memcpy(m_mpegTS, &m_udpBuffer[m_udpBufferIdx*sizeof(m_mpegTS)], sizeof(m_mpegTS));
m_udpBufferIdx++;
}
else if ((m_settings.m_source == DATVModSettings::SourceUDP)
&& ((m_udpSocket != nullptr) && m_udpSocket->hasPendingDatagrams())
)
{
updateUDPBufferUtilization();
// Get transport stream packets from UDP - buffer if more than one
QNetworkDatagram datagram = m_udpSocket->receiveDatagram();
QByteArray ba = datagram.data();
int size = ba.size();
char *data = ba.data();
if (size <= (int)sizeof(m_udpBuffer))
{
memcpy(m_mpegTS, data, sizeof(m_mpegTS));
if (size >= (int)sizeof(m_mpegTS)) {
memcpy(&m_udpBuffer[0], &data[sizeof(m_mpegTS)], size - sizeof(m_mpegTS));
}
m_udpBufferIdx = 0;
m_udpBufferCount = (size / sizeof(m_mpegTS)) - 1;
if (size % sizeof(m_mpegTS) != 0) {
qWarning() << "DATVModSource::modulateSample: UDP packet size (" << size << ") is not a multiple of " << sizeof(m_mpegTS);
}
}
else
{
qWarning() << "DATVModSource::modulateSample: UDP packet size (" << size << ") exceeds buffer size " << sizeof(m_udpBuffer) << ")";
}
m_udpByteCount += ba.size();
m_udpAbsByteCount += ba.size();
}
else if (m_settings.m_source == DATVModSettings::SourceImage)
{
if (m_frameCount == static_cast<int>(m_tsGenerator.get_buffer_size()/sizeof(m_mpegTS)))
{
int bitrate = static_cast<int>(getDVBSDataBitrate(m_settings) * 1.1f); // Add 10% margin
m_tsGenerator.generate_still_image_ts(m_settings.m_imageFileName.toStdString().c_str(), bitrate, m_settings.m_imageOverlayTimestamp, 1);
m_tsFileOK = true;
m_frameIdx = 0;
m_frameCount = 0;
}
// Read transport stream packet from generated image TS
uint8_t *tsPacket = m_tsGenerator.next_ts_packet();
if (tsPacket != nullptr)
{
memcpy(m_mpegTS, tsPacket, sizeof(m_mpegTS));
m_frameIdx++;
m_frameCount++;
}
else
{
// No more data
memset(m_mpegTS, 0xFF, sizeof(m_mpegTS));
m_mpegTS[0] = 0x47; // Sync byte
m_mpegTS[1] = 0x1F;
m_mpegTS[2] = 0xFF;
m_mpegTS[3] = 0x10;
}
}
else // Unsupported source or no more data
{
// Insert null packet. PID=0x1fff
memset(m_mpegTS, 0xFF, sizeof(m_mpegTS));
m_mpegTS[0] = 0x47; // Sync byte
m_mpegTS[1] = 0x1F;
m_mpegTS[2] = 0xFF;
m_mpegTS[3] = 0x10;
if (tsFileReady) {
m_frameCount++;
}
//qDebug() << "null " << tsFileReady << " " << (m_frameIdx/(m_frameCount+1.0f)) << " " << m_tsRatio;
}
if (m_settings.m_standard == DATVModSettings::DVB_S)
{
// Encode using DVB-S
m_symbolCount = m_dvbs.encode(m_mpegTS, m_iqSymbols);
}
else
{
// Encode using DVB-S2
m_symbolCount = m_dvbs2.s2_add_ts_frame((u8 *)m_mpegTS);
m_plFrame = m_dvbs2.pl_get_frame();
}
// Loop file if we reach the end
if ((m_settings.m_source == DATVModSettings::SourceFile)
&& (m_frameIdx*DVBS::tsPacketLen >= m_mpegTSSize)
&& m_settings.m_tsFilePlayLoop
)
{
m_mpegTSStream.clear();
m_mpegTSStream.seekg(0, std::ios::beg);
m_frameIdx = 0;
m_frameCount = 0;
}
m_symbolIdx = 0;
}
if (m_settings.m_modulation == DATVModSettings::BPSK)
{
// BPSK
i = m_pulseShapeI.filter(m_iqSymbols[m_symbolIdx*2+m_symbolSel] ? -1.0f : 1.0f);
q = 0.0f;
if (m_symbolSel == 1)
{
m_symbolIdx++;
m_symbolCount--;
m_symbolSel = 0;
}
else
{
m_symbolSel++;
}
}
else
{
// QPSK
if (m_settings.m_standard == DATVModSettings::DVB_S)
{
// Does the 45-degree rotation matter?
// Makes a little difference to amplitude of filter output, but we could scale that
i = m_pulseShapeI.filter(m_iqSymbols[m_symbolIdx*2] ? -1.0f : 1.0f);
q = m_pulseShapeQ.filter(m_iqSymbols[m_symbolIdx*2+1] ? -1.0f : 1.0f);
/*
int sym = (m_iqSymbols[m_symbolIdx*2] << 1) | m_iqSymbols[m_symbolIdx*2+1];
if (sym == 0)
{
i = m_pulseShapeI.filter(cos(M_PI/4));
q = m_pulseShapeQ.filter(sin(M_PI/4));
}
else if (sym == 1)
{
i = m_pulseShapeI.filter(cos(7*M_PI/4));
q = m_pulseShapeQ.filter(sin(7*M_PI/4));
}
else if (sym == 2)
{
i = m_pulseShapeI.filter(cos(3*M_PI/4));
q = m_pulseShapeQ.filter(sin(3*M_PI/4));
}
else if (sym == 3)
{
i = m_pulseShapeI.filter(cos(5*M_PI/4));
q = m_pulseShapeQ.filter(sin(5*M_PI/4));
}
*/
m_symbolIdx++;
m_symbolCount--;
}
else
{
// First 90 symbols of DVB-S2 are pi/2 BPSK, then remaining symbols are in specified modulation
i = m_pulseShapeI.filter(m_plFrame[m_symbolIdx].re/32767.0);
q = m_pulseShapeQ.filter(m_plFrame[m_symbolIdx].im/32767.0);
m_symbolIdx++;
m_symbolCount--;
}
}
}
else
{
i = m_pulseShapeI.filter(0.0f);
q = m_pulseShapeQ.filter(0.0f);
}
m_sampleIdx++;
if (m_sampleIdx >= m_samplesPerSymbol) {
m_sampleIdx = 0;
}
m_modSample.real(i);
m_modSample.imag(q);
// These levels aren't currently used in the GUI
Real t = std::abs(m_modSample);
calculateLevel(t);
}
void DATVModSource::calculateLevel(Real& sample)
{
if (m_levelCalcCount < m_levelNbSamples)
{
m_peakLevel = std::max(std::fabs(m_peakLevel), sample);
m_levelSum += sample * sample;
m_levelCalcCount++;
}
else
{
m_rmsLevel = std::sqrt(m_levelSum / m_levelNbSamples);
m_peakLevelOut = m_peakLevel;
m_peakLevel = 0.0f;
m_levelSum = 0.0f;
m_levelCalcCount = 0;
}
}
void DATVModSource::openTsFile(const QString& fileName)
{
m_tsFileOK = false;
m_mpegTSBitrate = getTSBitrate(fileName);
if (m_mpegTSBitrate > 0)
{
m_mpegTSStream.open(qPrintable(fileName), std::ifstream::binary);
if (m_mpegTSStream.is_open())
{
m_mpegTSStream.seekg (0, m_mpegTSStream.end);
m_mpegTSSize = m_mpegTSStream.tellg();
m_mpegTSStream.seekg (0, m_mpegTSStream.beg);
m_frameIdx = 0;
m_frameCount = 0;
m_tsFileOK = true;
}
checkBitrates();
}
else
qDebug() << "DATVModSource::openTsFile: Failed to get bitrate for transport stream file: " << fileName;
if (m_tsFileOK)
{
m_settings.m_tsFileName = fileName;
if (getMessageQueueToGUI())
{
DATVModReport::MsgReportTsFileSourceStreamData *report;
report = DATVModReport::MsgReportTsFileSourceStreamData::create(m_mpegTSBitrate, m_mpegTSSize);
getMessageQueueToGUI()->push(report);
}
}
else
{
m_settings.m_tsFileName.clear();
qDebug() << "DATVModSource::openTsFile: Cannot open file: " << fileName;
}
}
void DATVModSource::seekTsFileStream(int seekPercentage)
{
if (m_tsFileOK)
{
m_frameIdx = ((m_mpegTSSize / DVBS::tsPacketLen) * seekPercentage) / 100;
m_mpegTSStream.seekg (m_frameIdx * (std::streampos)DVBS::tsPacketLen, m_mpegTSStream.beg);
m_frameCount = (int)(m_frameIdx / m_tsRatio);
}
}
void DATVModSource::reportTsFileSourceStreamTiming()
{
int framesCount = m_tsFileOK ? m_frameIdx : 0;
if (getMessageQueueToGUI())
getMessageQueueToGUI()->push(DATVModReport::MsgReportTsFileSourceStreamTiming::create(framesCount));
}
void DATVModSource::reportUDPBitrate()
{
boost::chrono::duration<double> sec = boost::chrono::steady_clock::now() - m_udpTimingStart;
double seconds = sec.count();
int bitrate = seconds > 0.0 ? m_udpByteCount * 8 / seconds : 0;
m_udpTimingStart = boost::chrono::steady_clock::now();
m_udpByteCount = 0;
if (getMessageQueueToGUI()) {
getMessageQueueToGUI()->push(DATVModReport::MsgReportUDPBitrate::create(bitrate));
}
}
void DATVModSource::updateUDPBufferUtilization()
{
#ifdef _WIN32
u_long count;
ioctlsocket(m_udpSocket->socketDescriptor(), FIONREAD, &count);
if (count > m_udpMaxBufferUtilization) {
m_udpMaxBufferUtilization = count;
}
#else
// On linux, ioctl(s, SIOCINQ, &count); only returns length of first datagram, so we can't support this
#endif
}
void DATVModSource::reportUDPBufferUtilization()
{
// Report maximum utilization since last call
updateUDPBufferUtilization();
if (getMessageQueueToGUI())
{
getMessageQueueToGUI()->push(DATVModReport::MsgReportUDPBufferUtilization::create(
m_udpMaxBufferUtilization / (float)DATVModSettings::m_udpBufferSize * 100.0));
}
m_udpMaxBufferUtilization = 0;
}
void DATVModSource::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force)
{
qDebug() << "DATVModSource::applyChannelSettings:"
<< " channelSampleRate: " << channelSampleRate
<< " channelFrequencyOffset: " << channelFrequencyOffset;
if ((channelFrequencyOffset != m_channelFrequencyOffset) ||
(channelSampleRate != m_channelSampleRate) || force)
{
m_carrierNco.setFreq(channelFrequencyOffset, channelSampleRate);
}
if ((channelSampleRate != m_channelSampleRate) || force)
{
if (m_settings.m_symbolRate > 0)
{
m_sampleRate = (channelSampleRate/m_settings.m_symbolRate)*m_settings.m_symbolRate;
// Create interpolator if not integer multiple
if (m_sampleRate != channelSampleRate)
{
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) m_sampleRate / (Real) channelSampleRate;
m_interpolator.create(32, m_sampleRate, m_settings.m_rfBandwidth / 2.2f, 3.0);
}
if (getMessageQueueToGUI())
{
getMessageQueueToGUI()->push(DATVModReport::MsgReportRates::create(
channelSampleRate,
m_sampleRate,
getDVBSDataBitrate(m_settings)));
}
}
}
m_channelSampleRate = channelSampleRate;
m_channelFrequencyOffset = channelFrequencyOffset;
if (m_settings.m_symbolRate > 0)
m_samplesPerSymbol = m_channelSampleRate/m_settings.m_symbolRate;
m_pulseShapeI.create(m_settings.m_rollOff, 8, m_samplesPerSymbol, RootRaisedCosine<Real>::Energy);
m_pulseShapeQ.create(m_settings.m_rollOff, 8, m_samplesPerSymbol, RootRaisedCosine<Real>::Energy);
}
void DATVModSource::applySettings(const QStringList& settingsKeys, const DATVModSettings& settings, bool force)
{
qDebug() << "DATVModSource::applySettings:" << settings.getDebugString(settingsKeys, force);
if ((settingsKeys.contains("rfBandwidth") && settings.m_rfBandwidth != m_settings.m_rfBandwidth)
|| (settingsKeys.contains("modulation") && settings.m_modulation != m_settings.m_modulation)
|| (settingsKeys.contains("symbolRate") && settings.m_symbolRate != m_settings.m_symbolRate)
|| force)
{
if (settings.m_symbolRate > 0)
{
m_sampleRate = (m_channelSampleRate/settings.m_symbolRate)*settings.m_symbolRate;
if (m_sampleRate != m_channelSampleRate)
{
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) m_sampleRate / (Real) m_channelSampleRate;
m_interpolator.create(32, m_sampleRate, settings.m_rfBandwidth / 2.2f, 3.0);
}
if (getMessageQueueToGUI())
{
getMessageQueueToGUI()->push(DATVModReport::MsgReportRates::create(
m_channelSampleRate, m_sampleRate,
getDVBSDataBitrate(settings)));
}
}
else
qWarning() << "DATVModSource::applySettings: symbolRate must be greater than 0.";
}
if ((settingsKeys.contains("source") && settings.m_source != m_settings.m_source)
|| (settingsKeys.contains("udpAddress") && settings.m_udpAddress != m_settings.m_udpAddress)
|| (settingsKeys.contains("udpPort") && settings.m_udpPort != m_settings.m_udpPort)
|| force)
{
if (m_udpSocket)
{
m_udpSocket->close();
delete m_udpSocket;
m_udpSocket = nullptr;
}
if (settings.m_source == DATVModSettings::SourceUDP)
{
m_udpSocket = new QUdpSocket();
m_udpSocket->bind(QHostAddress(settings.m_udpAddress), settings.m_udpPort);
m_udpSocket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, DATVModSettings::m_udpBufferSize);
m_udpTimingStart = boost::chrono::steady_clock::now();
m_udpByteCount = 0;
m_udpAbsByteCount = 0;
}
}
if ((settingsKeys.contains("standard") && settings.m_standard != m_settings.m_standard)
|| (settingsKeys.contains("modulation") && settings.m_modulation != m_settings.m_modulation)
|| force)
{
m_symbolSel = 0;
m_symbolIdx = 0;
m_symbolCount = 0;
m_sampleIdx = 0;
}
if ((settingsKeys.contains("standard") && settings.m_standard != m_settings.m_standard)
|| (settingsKeys.contains("modulation") && settings.m_modulation != m_settings.m_modulation)
|| (settingsKeys.contains("fec") && settings.m_fec != m_settings.m_fec)
|| (settingsKeys.contains("rollOff") && settings.m_rollOff != m_settings.m_rollOff)
|| force)
{
if (settings.m_standard == DATVModSettings::DVB_S)
{
switch (settings.m_fec)
{
case DATVModSettings::FEC12:
m_dvbs.setCodeRate(DVBS::RATE_1_2);
break;
case DATVModSettings::FEC23:
m_dvbs.setCodeRate(DVBS::RATE_2_3);
break;
case DATVModSettings::FEC34:
m_dvbs.setCodeRate(DVBS::RATE_3_4);
break;
case DATVModSettings::FEC56:
m_dvbs.setCodeRate(DVBS::RATE_5_6);
break;
case DATVModSettings::FEC78:
m_dvbs.setCodeRate(DVBS::RATE_7_8);
break;
default:
qCritical() << "DATVModSource::applySettings: Unsupported FEC code rate for DVB-S: " << settings.m_fec;
break;
}
}
else
{
m_dvbs2Format.frame_type = FRAME_NORMAL;
m_dvbs2Format.pilots = 0; // PILOTS_OFF;
m_dvbs2Format.dummy_frame = 0;
m_dvbs2Format.null_deletion = 0;
m_dvbs2Format.intface = M_ACM; // Unused?
m_dvbs2Format.broadcasting = 1;
switch (settings.m_modulation)
{
case DATVModSettings::QPSK:
m_dvbs2Format.constellation = M_QPSK;
break;
case DATVModSettings::PSK8:
m_dvbs2Format.constellation = M_8PSK;
break;
case DATVModSettings::APSK16:
m_dvbs2Format.constellation = M_16APSK;
break;
case DATVModSettings::APSK32:
m_dvbs2Format.constellation = M_32APSK;
break;
default:
qDebug() << "DATVModSource::applySettings: Unsupported modulation for DVB-S2";
break;
}
switch (settings.m_fec)
{
case DATVModSettings::FEC12:
m_dvbs2Format.code_rate = CR_1_2;
break;
case DATVModSettings::FEC23:
m_dvbs2Format.code_rate = CR_2_3;
break;
case DATVModSettings::FEC34:
m_dvbs2Format.code_rate = CR_3_4;
break;
case DATVModSettings::FEC56:
m_dvbs2Format.code_rate = CR_5_6;
break;
case DATVModSettings::FEC45:
m_dvbs2Format.code_rate = CR_4_5;
break;
case DATVModSettings::FEC89:
m_dvbs2Format.code_rate = CR_8_9;
break;
case DATVModSettings::FEC910:
m_dvbs2Format.code_rate = CR_9_10;
break;
case DATVModSettings::FEC14:
m_dvbs2Format.code_rate = CR_1_4;
break;
case DATVModSettings::FEC13:
m_dvbs2Format.code_rate = CR_1_3;
break;
case DATVModSettings::FEC25:
m_dvbs2Format.code_rate = CR_2_5;
break;
case DATVModSettings::FEC35:
m_dvbs2Format.code_rate = CR_3_5;
break;
default:
qDebug() << "DATVModSource::getDVBSDataBitrate: Unsupported code rate for DVB-S2";
break;
}
if (settings.m_rollOff == 0.35f)
m_dvbs2Format.roll_off = RO_0_35;
else if (settings.m_rollOff == 0.25f)
m_dvbs2Format.roll_off = RO_0_25;
else
m_dvbs2Format.roll_off = RO_0_20;
m_dvbs2.s2_set_configure(&m_dvbs2Format);
}
if (getMessageQueueToGUI())
{
getMessageQueueToGUI()->push(DATVModReport::MsgReportRates::create(
m_channelSampleRate, m_sampleRate,
getDVBSDataBitrate(settings)));
}
}
if ((settingsKeys.contains("imageServiceProvider") && settings.m_imageServiceProvider != m_settings.m_imageServiceProvider) || force) {
m_tsGenerator.set_service_provider(settings.m_imageServiceProvider.toStdString());
}
if ((settingsKeys.contains("imageServiceName") && settings.m_imageServiceName != m_settings.m_imageServiceName) || force) {
m_tsGenerator.set_service_name(settings.m_imageServiceName.toStdString());
}
if ((settingsKeys.contains("imageCodec") && settings.m_imageCodec != m_settings.m_imageCodec) || force) {
m_tsGenerator.set_codec(settings.m_imageCodec);
}
if (force) {
m_settings = settings;
} else {
m_settings.applySettings(settingsKeys, settings);
}
if (m_settings.m_symbolRate > 0)
m_samplesPerSymbol = m_channelSampleRate/m_settings.m_symbolRate;
m_pulseShapeI.create(m_settings.m_rollOff, 8, m_samplesPerSymbol, RootRaisedCosine<Real>::Energy);
m_pulseShapeQ.create(m_settings.m_rollOff, 8, m_samplesPerSymbol, RootRaisedCosine<Real>::Energy);
checkBitrates();
}