Local Sink: auto detect Local Input devices and fix crashes in most situations. Part of #871

pull/1539/head
f4exb 2022-12-03 13:33:38 +01:00
rodzic 6cc15442e2
commit b1ba80b847
14 zmienionych plików z 218 dodań i 169 usunięć

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 13 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 13 KiB

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -34,6 +34,7 @@
#include "dsp/hbfilterchainconverter.h"
#include "dsp/devicesamplemimo.h"
#include "device/deviceapi.h"
#include "device/deviceset.h"
#include "feature/feature.h"
#include "settings/serializable.h"
#include "maincore.h"
@ -42,6 +43,7 @@
#include "localsink.h"
MESSAGE_CLASS_DEFINITION(LocalSink::MsgConfigureLocalSink, Message)
MESSAGE_CLASS_DEFINITION(LocalSink::MsgReportDevices, Message)
const char* const LocalSink::m_channelIdURI = "sdrangel.channel.localsink";
const char* const LocalSink::m_channelId = "LocalSink";
@ -75,7 +77,19 @@ LocalSink::LocalSink(DeviceAPI *deviceAPI) :
this,
&LocalSink::handleIndexInDeviceSetChanged
);
start();
// Update device list when devices are added or removed
QObject::connect(
MainCore::instance(),
&MainCore::deviceSetAdded,
this,
&LocalSink::updateDeviceSetList
);
QObject::connect(
MainCore::instance(),
&MainCore::deviceSetRemoved,
this,
&LocalSink::updateDeviceSetList
);
}
LocalSink::~LocalSink()
@ -89,7 +103,7 @@ LocalSink::~LocalSink()
delete m_networkManager;
m_deviceAPI->removeChannelSinkAPI(this);
m_deviceAPI->removeChannelSink(this);
stop();
stopProcessing();
}
void LocalSink::setDeviceAPI(DeviceAPI *deviceAPI)
@ -119,12 +133,18 @@ void LocalSink::feed(const SampleVector::const_iterator& begin, const SampleVect
}
void LocalSink::start()
{ }
void LocalSink::stop()
{ }
void LocalSink::startProcessing()
{
if (m_running) {
return;
}
qDebug("LocalSink::start");
qDebug("LocalSink::startProcessing");
m_thread = new QThread(this);
m_basebandSink = new LocalSinkBaseband();
m_basebandSink->moveToThread(m_thread);
@ -135,19 +155,24 @@ void LocalSink::start()
m_basebandSink->reset();
m_thread->start();
LocalSinkBaseband::MsgConfigureLocalSinkBaseband *msg = LocalSinkBaseband::MsgConfigureLocalSinkBaseband::create(m_settings, true);
m_basebandSink->getInputMessageQueue()->push(msg);
DeviceSampleSource *deviceSource = getLocalDevice(m_settings.m_localDeviceIndex);
LocalSinkBaseband::MsgConfigureLocalDeviceSampleSource *msgDevice =
LocalSinkBaseband::MsgConfigureLocalDeviceSampleSource::create(deviceSource);
m_basebandSink->getInputMessageQueue()->push(msgDevice);
LocalSinkBaseband::MsgConfigureLocalSinkBaseband *msgConfig = LocalSinkBaseband::MsgConfigureLocalSinkBaseband::create(m_settings, true);
m_basebandSink->getInputMessageQueue()->push(msgConfig);
m_running = true;
}
void LocalSink::stop()
void LocalSink::stopProcessing()
{
if (!m_running) {
return;
}
qDebug("LocalSink::stop");
qDebug("LocalSink::stopProcessing");
m_running = false;
m_thread->exit();
m_thread->wait();
@ -218,27 +243,15 @@ bool LocalSink::deserialize(const QByteArray& data)
}
}
void LocalSink::getLocalDevices(std::vector<uint32_t>& indexes)
DeviceSampleSource *LocalSink::getLocalDevice(int index)
{
indexes.clear();
DSPEngine *dspEngine = DSPEngine::instance();
for (uint32_t i = 0; i < dspEngine->getDeviceSourceEnginesNumber(); i++)
{
DSPDeviceSourceEngine *deviceSourceEngine = dspEngine->getDeviceSourceEngineByIndex(i);
DeviceSampleSource *deviceSource = deviceSourceEngine->getSource();
if (deviceSource->getDeviceDescription() == "LocalInput") {
indexes.push_back(i);
}
if (index < 0) {
return nullptr;
}
}
DeviceSampleSource *LocalSink::getLocalDevice(uint32_t index)
{
DSPEngine *dspEngine = DSPEngine::instance();
if (index < dspEngine->getDeviceSourceEnginesNumber())
if (index < (int) dspEngine->getDeviceSourceEnginesNumber())
{
DSPDeviceSourceEngine *deviceSourceEngine = dspEngine->getDeviceSourceEngineByIndex(index);
DeviceSampleSource *deviceSource = deviceSourceEngine->getSource();
@ -266,7 +279,7 @@ DeviceSampleSource *LocalSink::getLocalDevice(uint32_t index)
return nullptr;
}
void LocalSink::propagateSampleRateAndFrequency(uint32_t index, uint32_t log2Decim)
void LocalSink::propagateSampleRateAndFrequency(int index, uint32_t log2Decim)
{
qDebug() << "LocalSink::propagateSampleRateAndFrequency:"
<< " index: " << index
@ -329,10 +342,10 @@ void LocalSink::applySettings(const LocalSinkSettings& settings, bool force)
{
reverseAPIKeys.append("play");
if (m_running)
{
LocalSinkBaseband::MsgConfigureLocalSinkWork *msg = LocalSinkBaseband::MsgConfigureLocalSinkWork::create(settings.m_play);
m_basebandSink->getInputMessageQueue()->push(msg);
if (settings.m_play) {
startProcessing();
} else {
stopProcessing();
}
}
@ -682,3 +695,67 @@ void LocalSink::handleIndexInDeviceSetChanged(int index)
.arg(index);
m_basebandSink->setFifoLabel(fifoLabel);
}
void LocalSink::updateDeviceSetList()
{
MainCore *mainCore = MainCore::instance();
std::vector<DeviceSet*>& deviceSets = mainCore->getDeviceSets();
std::vector<DeviceSet*>::const_iterator it = deviceSets.begin();
m_localInputDeviceIndexes.clear();
unsigned int deviceIndex = 0;
for (; it != deviceSets.end(); ++it, deviceIndex++)
{
DSPDeviceSourceEngine *deviceSourceEngine = (*it)->m_deviceSourceEngine;
if (deviceSourceEngine)
{
DeviceSampleSource *deviceSource = deviceSourceEngine->getSource();
if (deviceSource->getDeviceDescription() == "LocalInput") {
m_localInputDeviceIndexes.append(deviceIndex);
}
}
}
if (m_guiMessageQueue)
{
MsgReportDevices *msg = MsgReportDevices::create();
msg->getDeviceSetIndexes() = m_localInputDeviceIndexes;
m_guiMessageQueue->push(msg);
}
LocalSinkSettings settings = m_settings;
int newIndexInList;
if (it != deviceSets.begin())
{
if (m_settings.m_localDeviceIndex < 0) {
newIndexInList = 0;
} else if (m_settings.m_localDeviceIndex >= m_localInputDeviceIndexes.size()) {
newIndexInList = m_localInputDeviceIndexes.size() - 1;
} else {
newIndexInList = m_settings.m_localDeviceIndex;
}
}
else
{
newIndexInList = -1;
}
if (newIndexInList < 0) {
settings.m_localDeviceIndex = -1; // means no device
} else {
settings.m_localDeviceIndex = m_localInputDeviceIndexes[newIndexInList];
}
qDebug("LocalSink::updateDeviceSetLists: new device index: %d device: %d", newIndexInList, settings.m_localDeviceIndex);
applySettings(settings);
if (m_guiMessageQueue)
{
MsgConfigureLocalSink *msg = MsgConfigureLocalSink::create(m_settings, false);
m_guiMessageQueue->push(msg);
}
}

Wyświetl plik

@ -45,8 +45,7 @@ public:
const LocalSinkSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureLocalSink* create(const LocalSinkSettings& settings, bool force)
{
static MsgConfigureLocalSink* create(const LocalSinkSettings& settings, bool force) {
return new MsgConfigureLocalSink(settings, force);
}
@ -61,6 +60,24 @@ public:
{ }
};
class MsgReportDevices : public Message {
MESSAGE_CLASS_DECLARATION
public:
QList<int>& getDeviceSetIndexes() { return m_deviceSetIndexes; }
static MsgReportDevices* create() {
return new MsgReportDevices();
}
private:
QList<int> m_deviceSetIndexes;
MsgReportDevices() :
Message()
{ }
};
LocalSink(DeviceAPI *deviceAPI);
virtual ~LocalSink();
virtual void destroy() { delete this; }
@ -116,8 +133,8 @@ public:
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response);
void getLocalDevices(std::vector<uint32_t>& indexes);
uint32_t getNumberOfDeviceStreams() const;
const QList<int>& getDeviceSetList() { return m_localInputDeviceIndexes; }
static const char* const m_channelIdURI;
static const char* const m_channelId;
@ -128,6 +145,7 @@ private:
LocalSinkBaseband *m_basebandSink;
bool m_running;
LocalSinkSettings m_settings;
QList<int> m_localInputDeviceIndexes;
uint64_t m_centerFrequency;
int64_t m_frequencyOffset;
@ -138,10 +156,13 @@ private:
virtual bool handleMessage(const Message& cmd);
void applySettings(const LocalSinkSettings& settings, bool force = false);
void propagateSampleRateAndFrequency(uint32_t index, uint32_t log2Decim);
void propagateSampleRateAndFrequency(int index, uint32_t log2Decim);
static void validateFilterChainHash(LocalSinkSettings& settings);
void calculateFrequencyOffset(uint32_t log2Decim, uint32_t filterChainHash);
DeviceSampleSource *getLocalDevice(uint32_t index);
void updateDeviceSetList();
DeviceSampleSource *getLocalDevice(int index);
void startProcessing();
void stopProcessing();
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const LocalSinkSettings& settings, bool force);
void sendChannelSettings(

Wyświetl plik

@ -24,7 +24,6 @@
#include "localsinkbaseband.h"
MESSAGE_CLASS_DEFINITION(LocalSinkBaseband::MsgConfigureLocalSinkBaseband, Message)
MESSAGE_CLASS_DEFINITION(LocalSinkBaseband::MsgConfigureLocalSinkWork, Message)
MESSAGE_CLASS_DEFINITION(LocalSinkBaseband::MsgConfigureLocalDeviceSampleSource, Message)
LocalSinkBaseband::LocalSinkBaseband() :
@ -43,10 +42,12 @@ LocalSinkBaseband::LocalSinkBaseband() :
);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
m_sink.start(m_localSampleSource);
}
LocalSinkBaseband::~LocalSinkBaseband()
{
m_sink.stop();
delete m_channelizer;
}
@ -123,20 +124,6 @@ bool LocalSinkBaseband::handleMessage(const Message& cmd)
return true;
}
else if (MsgConfigureLocalSinkWork::match(cmd))
{
QMutexLocker mutexLocker(&m_mutex);
MsgConfigureLocalSinkWork& conf = (MsgConfigureLocalSinkWork&) cmd;
qDebug() << "LocalSinkBaseband::handleMessage: MsgConfigureLocalSinkWork: " << conf.isWorking();
if (conf.isWorking()) {
m_sink.start(m_localSampleSource);
} else {
m_sink.stop();
}
return true;
}
else if (MsgConfigureLocalDeviceSampleSource::match(cmd))
{
QMutexLocker mutexLocker(&m_mutex);

Wyświetl plik

@ -57,26 +57,6 @@ public:
{ }
};
class MsgConfigureLocalSinkWork : public Message {
MESSAGE_CLASS_DECLARATION
public:
bool isWorking() const { return m_working; }
static MsgConfigureLocalSinkWork* create(bool working)
{
return new MsgConfigureLocalSinkWork(working);
}
private:
bool m_working;
MsgConfigureLocalSinkWork(bool working) :
Message(),
m_working(working)
{ }
};
class MsgConfigureLocalDeviceSampleSource : public Message {
MESSAGE_CLASS_DECLARATION

Wyświetl plik

@ -22,7 +22,6 @@
#include "gui/devicestreamselectiondialog.h"
#include "dsp/hbfilterchainconverter.h"
#include "dsp/dspcommands.h"
#include "mainwindow.h"
#include "localsinkgui.h"
#include "localsink.h"
@ -53,7 +52,6 @@ QByteArray LocalSinkGUI::serialize() const
bool LocalSinkGUI::deserialize(const QByteArray& data)
{
updateLocalDevices();
if (m_settings.deserialize(data))
{
@ -90,6 +88,12 @@ bool LocalSinkGUI::handleMessage(const Message& message)
blockApplySettings(false);
return true;
}
else if (LocalSink::MsgReportDevices::match(message))
{
LocalSink::MsgReportDevices& report = (LocalSink::MsgReportDevices&) message;
updateDeviceSetList(report.getDeviceSetIndexes());
return true;
}
else
{
return false;
@ -131,7 +135,7 @@ LocalSinkGUI::LocalSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages()));
updateLocalDevices();
updateDeviceSetList(m_localSink->getDeviceSetList());
displaySettings();
makeUIConnections();
applySettings(true);
@ -199,18 +203,6 @@ void LocalSinkGUI::displayRateAndShift()
m_channelMarker.setBandwidth(channelSampleRate);
}
void LocalSinkGUI::updateLocalDevices()
{
std::vector<uint32_t> localDevicesIndexes;
m_localSink->getLocalDevices(localDevicesIndexes);
ui->localDevice->clear();
std::vector<uint32_t>::const_iterator it = localDevicesIndexes.begin();
for (; it != localDevicesIndexes.end(); ++it) {
ui->localDevice->addItem(tr("%1").arg(*it), QVariant(*it));
}
}
int LocalSinkGUI::getLocalDeviceIndexInCombo(int localDeviceIndex)
{
int index = 0;
@ -224,7 +216,6 @@ int LocalSinkGUI::getLocalDeviceIndexInCombo(int localDeviceIndex)
return -1;
}
void LocalSinkGUI::leaveEvent(QEvent* event)
{
m_channelMarker.setHighlighted(false);
@ -243,8 +234,7 @@ void LocalSinkGUI::handleSourceMessages()
while ((message = getInputMessageQueue()->pop()) != 0)
{
if (handleMessage(*message))
{
if (handleMessage(*message)) {
delete message;
}
}
@ -306,6 +296,21 @@ void LocalSinkGUI::onMenuDialogCalled(const QPoint &p)
resetContextMenuType();
}
void LocalSinkGUI::updateDeviceSetList(const QList<int>& deviceSetIndexes)
{
QList<int>::const_iterator it = deviceSetIndexes.begin();
ui->localDevice->blockSignals(true);
ui->localDevice->clear();
for (; it != deviceSetIndexes.end(); ++it) {
ui->localDevice->addItem(QString("R%1").arg(*it), *it);
}
ui->localDevice->blockSignals(false);
}
void LocalSinkGUI::on_decimationFactor_currentIndexChanged(int index)
{
m_settings.m_log2Decim = index;
@ -320,18 +325,10 @@ void LocalSinkGUI::on_position_valueChanged(int value)
void LocalSinkGUI::on_localDevice_currentIndexChanged(int index)
{
m_settings.m_localDeviceIndex = ui->localDevice->itemData(index).toInt();
applySettings();
}
void LocalSinkGUI::on_localDevicesRefresh_clicked(bool checked)
{
(void) checked;
updateLocalDevices();
int index = getLocalDeviceIndexInCombo(m_settings.m_localDeviceIndex);
if (index >= 0) {
ui->localDevice->setCurrentIndex(index);
if (index >= 0)
{
m_settings.m_localDeviceIndex = ui->localDevice->currentData().toInt();
applySettings();
}
}
@ -379,7 +376,6 @@ void LocalSinkGUI::makeUIConnections()
QObject::connect(ui->decimationFactor, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &LocalSinkGUI::on_decimationFactor_currentIndexChanged);
QObject::connect(ui->position, &QSlider::valueChanged, this, &LocalSinkGUI::on_position_valueChanged);
QObject::connect(ui->localDevice, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &LocalSinkGUI::on_localDevice_currentIndexChanged);
QObject::connect(ui->localDevicesRefresh, &QPushButton::clicked, this, &LocalSinkGUI::on_localDevicesRefresh_clicked);
QObject::connect(ui->localDevicePlay, &ButtonSwitch::toggled, this, &LocalSinkGUI::on_localDevicePlay_toggled);
}

Wyświetl plik

@ -84,11 +84,11 @@ private:
void applySettings(bool force = false);
void displaySettings();
void displayRateAndShift();
void updateLocalDevices();
int getLocalDeviceIndexInCombo(int localDeviceIndex);
bool handleMessage(const Message& message);
void makeUIConnections();
void updateAbsoluteCenterFrequency();
void updateDeviceSetList(const QList<int>& deviceSetIndexes);
int getLocalDeviceIndexInCombo(int localDeviceIndex);
void leaveEvent(QEvent*);
void enterEvent(EnterEventType*);
@ -101,7 +101,6 @@ private slots:
void on_decimationFactor_currentIndexChanged(int index);
void on_position_valueChanged(int value);
void on_localDevice_currentIndexChanged(int index);
void on_localDevicesRefresh_clicked(bool checked);
void on_localDevicePlay_toggled(bool checked);
void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p);

Wyświetl plik

@ -281,30 +281,10 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="localDevicesRefresh">
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Refresh indexes of available local devices</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/recycle.png</normaloff>:/recycle.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="localDevicePlay">
<property name="toolTip">
<string>Start/Stop sink</string>
<string>Start/Stop processing</string>
</property>
<property name="text">
<string/>
@ -335,17 +315,17 @@
</widget>
</widget>
<customwidgets>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
<customwidget>
<class>RollupContents</class>
<extends>QWidget</extends>
<header>gui/rollupcontents.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>

Wyświetl plik

@ -30,7 +30,7 @@ LocalSinkSettings::LocalSinkSettings()
void LocalSinkSettings::resetToDefaults()
{
m_localDeviceIndex = 0;
m_localDeviceIndex = -1;
m_rgbColor = QColor(140, 4, 4).rgb();
m_title = "Local sink";
m_log2Decim = 0;
@ -51,7 +51,7 @@ void LocalSinkSettings::resetToDefaults()
QByteArray LocalSinkSettings::serialize() const
{
SimpleSerializer s(1);
s.writeU32(1, m_localDeviceIndex);
s.writeS32(1, m_localDeviceIndex);
if (m_channelMarker) {
s.writeBlob(2, m_channelMarker->serialize());
@ -95,7 +95,7 @@ bool LocalSinkSettings::deserialize(const QByteArray& data)
QString strtmp;
QByteArray bytetmp;
d.readU32(1, &m_localDeviceIndex, 0);
d.readS32(1, &m_localDeviceIndex, -1);
if (m_channelMarker)
{

Wyświetl plik

@ -25,7 +25,7 @@ class Serializable;
struct LocalSinkSettings
{
uint32_t m_localDeviceIndex;
int m_localDeviceIndex;
quint32 m_rgbColor;
QString m_title;
uint32_t m_log2Decim;

Wyświetl plik

@ -26,12 +26,13 @@
#include "localsinksink.h"
LocalSinkSink::LocalSinkSink() :
m_sinkWorker(nullptr),
m_running(false),
m_centerFrequency(0),
m_frequencyOffset(0),
m_sampleRate(48000),
m_deviceSampleRate(48000)
m_deviceSource(nullptr),
m_sinkWorker(nullptr),
m_running(false),
m_centerFrequency(0),
m_frequencyOffset(0),
m_sampleRate(48000),
m_deviceSampleRate(48000)
{
m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(4000000));
applySettings(m_settings, true);
@ -43,34 +44,39 @@ LocalSinkSink::~LocalSinkSink()
void LocalSinkSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
{
m_sampleFifo.write(begin, end);
if (m_running && m_deviceSource) {
m_deviceSource->getSampleFifo()->write(begin, end);
}
// m_sampleFifo.write(begin, end);
}
void LocalSinkSink::start(DeviceSampleSource *deviceSource)
{
qDebug("LocalSinkSink::start");
qDebug("LocalSinkSink::start: deviceSource: %p", deviceSource);
if (m_running) {
stop();
}
m_sinkWorker = new LocalSinkWorker();
m_sinkWorker->moveToThread(&m_sinkWorkerThread);
m_sinkWorker->setSampleFifo(&m_sampleFifo);
m_deviceSource = deviceSource;
// TODO: We'll see later if a worker is really needed
// m_sinkWorker = new LocalSinkWorker();
// m_sinkWorker->moveToThread(&m_sinkWorkerThread);
// m_sinkWorker->setSampleFifo(&m_sampleFifo);
if (deviceSource) {
m_sinkWorker->setDeviceSampleFifo(deviceSource->getSampleFifo());
}
// if (deviceSource) {
// m_sinkWorker->setDeviceSampleFifo(deviceSource->getSampleFifo());
// }
QObject::connect(
&m_sampleFifo,
&SampleSinkFifo::dataReady,
m_sinkWorker,
&LocalSinkWorker::handleData,
Qt::QueuedConnection
);
// QObject::connect(
// &m_sampleFifo,
// &SampleSinkFifo::dataReady,
// m_sinkWorker,
// &LocalSinkWorker::handleData,
// Qt::QueuedConnection
// );
startWorker();
// startWorker();
m_running = true;
}
@ -78,21 +84,23 @@ void LocalSinkSink::stop()
{
qDebug("LocalSinkSink::stop");
QObject::disconnect(
&m_sampleFifo,
&SampleSinkFifo::dataReady,
m_sinkWorker,
&LocalSinkWorker::handleData
);
// TODO: We'll see later if a worker is really needed
// QObject::disconnect(
// &m_sampleFifo,
// &SampleSinkFifo::dataReady,
// m_sinkWorker,
// &LocalSinkWorker::handleData
// );
if (m_sinkWorker != 0)
{
stopWorker();
m_sinkWorker->deleteLater();
m_sinkWorker = nullptr;
}
// if (m_sinkWorker != 0)
// {
// stopWorker();
// m_sinkWorker->deleteLater();
// m_sinkWorker = nullptr;
// }
m_running = false;
m_deviceSource = nullptr;
}
void LocalSinkSink::startWorker()

Wyświetl plik

@ -43,6 +43,7 @@ public:
void setSampleRate(int sampleRate);
private:
DeviceSampleSource *m_deviceSource;
SampleSinkFifo m_sampleFifo;
LocalSinkSettings m_settings;
LocalSinkWorker *m_sinkWorker;

Wyświetl plik

@ -12,7 +12,7 @@ These Local Sinks can then be coupled with two Local Input device source plugins
Note that because it uses only the channelizer half band filter chain to achieve decimation and center frequency shift you have a limited choice on the center frequencies that may be used (similarly to the Remote Sink). The available center frequencies depend on the baseband sample rate, the channel decimation and the filter chain that is used so you have to play with these parameters to obtain a suitable center frequency and pass band.
<b>&#9888; Important warning</b> When closing the application or before closing the local input device the local sink is connected to you have to stop the device where the local sink operates. This is because there is no reverse link for the local input to notify the local sink that it closes. Therefore closing the local input while the local sink runs will crash the program.
<b>&#9888; Important warning</b> When closing the application or before closing the local input device the local sink is connected it is recommended to stop processing on the local sink (7). Depending on the sequence by which the devices have been created closing the local input while the local sink runs may crash the program.
<h2>Interface</h2>
@ -52,6 +52,6 @@ The slider moves the channel center frequency roughly from the lower to the high
This selects the index of the Local Input source where to send the I/Q samples. The list can be refreshed with the next button (7)
<h3>7: Refresh local input devices list</h2>
<h3>7: Start/stop processing</h2>
Use this button to refresh the list of Local Input sources indexes.
Use this button to start or stop processing.