diff --git a/plugins/samplesource/filesource/filesourcethread.h b/plugins/samplesource/filesource/filesourcethread.h index 9c92c275f..ca777a241 100644 --- a/plugins/samplesource/filesource/filesourcethread.h +++ b/plugins/samplesource/filesource/filesourcethread.h @@ -26,11 +26,12 @@ #include #include -#include "../../../sdrbase/dsp/samplesinkfifo.h" #include "dsp/inthalfbandfilter.h" #define FILESOURCE_THROTTLE_MS 50 +class SampleSinkFifo; + class FileSourceThread : public QThread { Q_OBJECT diff --git a/sdrbase/plugin/pluginapi.cpp b/sdrbase/plugin/pluginapi.cpp index c2446a06e..43bae187e 100644 --- a/sdrbase/plugin/pluginapi.cpp +++ b/sdrbase/plugin/pluginapi.cpp @@ -23,6 +23,21 @@ PluginAPI::ChannelRegistrations *PluginAPI::getRxChannelRegistrations() return m_pluginManager->getRxChannelRegistrations(); } +void PluginAPI::registerTxChannel(const QString& channelName, PluginInterface* plugin) +{ + m_pluginManager->registerTxChannel(channelName, plugin); +} + +void PluginAPI::registerSampleSink(const QString& sinkName, PluginInterface* plugin) +{ + m_pluginManager->registerSampleSource(sinkName, plugin); +} + +PluginAPI::ChannelRegistrations *PluginAPI::getTxChannelRegistrations() +{ + return m_pluginManager->getTxChannelRegistrations(); +} + PluginAPI::PluginAPI(PluginManager* pluginManager, MainWindow* mainWindow) : QObject(mainWindow), diff --git a/sdrbase/plugin/pluginapi.h b/sdrbase/plugin/pluginapi.h index 3c03fbca4..85c3879c1 100644 --- a/sdrbase/plugin/pluginapi.h +++ b/sdrbase/plugin/pluginapi.h @@ -33,13 +33,20 @@ public: // MainWindow access MessageQueue* getMainWindowMessageQueue(); - // Channel stuff + // Rx Channel stuff void registerRxChannel(const QString& channelName, PluginInterface* plugin); ChannelRegistrations *getRxChannelRegistrations(); + // Tx Channel stuff + void registerTxChannel(const QString& channelName, PluginInterface* plugin); + ChannelRegistrations *getTxChannelRegistrations(); + // Sample Source stuff void registerSampleSource(const QString& sourceName, PluginInterface* plugin); + // Sample Sink stuff + void registerSampleSink(const QString& sinkName, PluginInterface* plugin); + // R/O access to main window const MainWindow* getMainWindow() const { return m_mainWindow; } diff --git a/sdrbase/plugin/pluginmanager.cpp b/sdrbase/plugin/pluginmanager.cpp index 7d8cfcc9d..000a8dcb7 100644 --- a/sdrbase/plugin/pluginmanager.cpp +++ b/sdrbase/plugin/pluginmanager.cpp @@ -1,4 +1,21 @@ -#include +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 Edouard Griffiths, F4EXB // +// // +// 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 // +// // +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "device/devicesourceapi.h" +#include "device/devicesinkapi.h" #include #include #include @@ -12,11 +29,13 @@ #include "util/message.h" #include -#include "../dsp/dspdevicesourceengine.h" +#include "dsp/dspdevicesourceengine.h" +#include "dsp/dspdevicesinkengine.h" const QString PluginManager::m_sdrDaemonDeviceTypeID = "sdrangel.samplesource.sdrdaemon"; const QString PluginManager::m_sdrDaemonFECDeviceTypeID = "sdrangel.samplesource.sdrdaemonfec"; const QString PluginManager::m_fileSourceDeviceTypeID = "sdrangel.samplesource.filesource"; +const QString PluginManager::m_fileSinkDeviceTypeID = "sdrangel.samplesink.filesink"; PluginManager::PluginManager(MainWindow* mainWindow, QObject* parent) : QObject(parent), @@ -57,6 +76,11 @@ void PluginManager::registerRxChannel(const QString& channelName, PluginInterfac m_rxChannelRegistrations.append(PluginAPI::ChannelRegistration(channelName, plugin)); } +void PluginManager::registerTxChannel(const QString& channelName, PluginInterface* plugin) +{ + m_txChannelRegistrations.append(PluginAPI::ChannelRegistration(channelName, plugin)); +} + void PluginManager::registerSampleSource(const QString& sourceName, PluginInterface* plugin) { qDebug() << "PluginManager::registerSampleSource " @@ -66,6 +90,15 @@ void PluginManager::registerSampleSource(const QString& sourceName, PluginInterf m_sampleSourceRegistrations.append(SamplingDeviceRegistration(sourceName, plugin)); } +void PluginManager::registerSampleSink(const QString& sinkName, PluginInterface* plugin) +{ + qDebug() << "PluginManager::registerSampleSink " + << plugin->getPluginDescriptor().displayedName.toStdString().c_str() + << " with source name " << sinkName.toStdString().c_str(); + + m_sampleSinkRegistrations.append(SamplingDeviceRegistration(sinkName, plugin)); +} + void PluginManager::updateSampleSourceDevices() { m_sampleSourceDevices.clear(); @@ -85,6 +118,25 @@ void PluginManager::updateSampleSourceDevices() } } +void PluginManager::updateSampleSinkDevices() +{ + m_sampleSinkDevices.clear(); + + for(int i = 0; i < m_sampleSinkRegistrations.count(); ++i) + { + PluginInterface::SamplingDevices ssd = m_sampleSinkRegistrations[i].m_plugin->enumSampleSinks(); + + for(int j = 0; j < ssd.count(); ++j) + { + m_sampleSinkDevices.append(SamplingDevice(m_sampleSinkRegistrations[i].m_plugin, + ssd[j].displayedName, + ssd[j].id, + ssd[j].serial, + ssd[j].sequence)); + } + } +} + void PluginManager::duplicateLocalSampleSourceDevices(uint deviceUID) { if (deviceUID == 0) { @@ -169,6 +221,42 @@ void PluginManager::duplicateLocalSampleSourceDevices(uint deviceUID) } } +void PluginManager::duplicateLocalSampleSinkDevices(uint deviceUID) +{ + if (deviceUID == 0) { + return; + } + + SamplingDevice *fileSinkSSD0 = 0; + bool duplicateFileSink = true; + + for(int i = 0; i < m_sampleSinkDevices.count(); ++i) + { + if (m_sampleSinkDevices[i].m_deviceId == m_fileSinkDeviceTypeID) // File Sink + { + if (m_sampleSinkDevices[i].m_deviceSequence == 0) { // reference to device 0 + fileSinkSSD0 = &m_sampleSinkDevices[i]; + } + else if (m_sampleSinkDevices[i].m_deviceSequence == deviceUID) { // already there + duplicateFileSink = false; + } + } + } + + if (fileSinkSSD0 && duplicateFileSink) // append item for a new instance + { + m_sampleSinkDevices.append( + SamplingDevice( + fileSinkSSD0->m_plugin, + QString("FileSink[%1]").arg(deviceUID), + fileSinkSSD0->m_deviceId, + fileSinkSSD0->m_deviceSerial, + deviceUID + ) + ); + } +} + void PluginManager::fillSampleSourceSelector(QComboBox* comboBox, uint deviceUID) { comboBox->clear(); @@ -189,6 +277,24 @@ void PluginManager::fillSampleSourceSelector(QComboBox* comboBox, uint deviceUID } } +void PluginManager::fillSampleSinkSelector(QComboBox* comboBox, uint deviceUID) +{ + comboBox->clear(); + + for(int i = 0; i < m_sampleSinkDevices.count(); i++) + { + // For "local" devices show only ones that concern this device set + if (m_sampleSinkDevices[i].m_deviceId == m_fileSinkDeviceTypeID) + { + if (deviceUID != m_sampleSinkDevices[i].m_deviceSequence) { + continue; + } + } + + comboBox->addItem(m_sampleSinkDevices[i].m_displayName, qVariantFromValue((void *) &m_sampleSinkDevices[i])); + } +} + int PluginManager::selectSampleSourceByIndex(int index, DeviceSourceAPI *deviceAPI) { qDebug("PluginManager::selectSampleSourceByIndex: index: %d", index); @@ -229,6 +335,46 @@ int PluginManager::selectSampleSourceByIndex(int index, DeviceSourceAPI *deviceA return index; } +int PluginManager::selectSampleSinkByIndex(int index, DeviceSinkAPI *deviceAPI) +{ + qDebug("PluginManager::selectSampleSinkByIndex: index: %d", index); + + if (m_sampleSinkDevices.count() == 0) + { + return -1; + } + + if (index < 0) + { + return -1; + } + + if (index >= m_sampleSinkDevices.count()) + { + index = 0; + } + + qDebug() << "PluginManager::selectSampleSinkByIndex: m_sampleSink at index " << index + << " id: " << m_sampleSinkDevices[index].m_deviceId.toStdString().c_str() + << " ser: " << m_sampleSinkDevices[index].m_deviceSerial.toStdString().c_str() + << " seq: " << m_sampleSinkDevices[index].m_deviceSequence; + + deviceAPI->stopGeneration(); + deviceAPI->setSampleSinkPluginGUI(0); // this effectively destroys the previous GUI if it exists + + QWidget *gui; + PluginGUI *pluginGUI = m_sampleSinkDevices[index].m_plugin->createSampleSinkPluginGUI(m_sampleSinkDevices[index].m_deviceId, &gui, deviceAPI); + + // m_sampleSourcePluginGUI = pluginGUI; + deviceAPI->setSampleSinkSequence(m_sampleSinkDevices[index].m_deviceSequence); + deviceAPI->setSampleSinkId(m_sampleSinkDevices[index].m_deviceId); + deviceAPI->setSampleSinkSerial(m_sampleSinkDevices[index].m_deviceSerial); + deviceAPI->setSampleSinkPluginGUI(pluginGUI); + deviceAPI->setOutputGUI(gui, m_sampleSinkDevices[index].m_displayName); + + return index; +} + int PluginManager::selectFirstSampleSource(const QString& sourceId, DeviceSourceAPI *deviceAPI) { qDebug("PluginManager::selectFirstSampleSource by id: [%s]", qPrintable(sourceId)); @@ -279,6 +425,56 @@ int PluginManager::selectFirstSampleSource(const QString& sourceId, DeviceSource return index; } +int PluginManager::selectFirstSampleSink(const QString& sinkId, DeviceSinkAPI *deviceAPI) +{ + qDebug("PluginManager::selectFirstSampleSink by id: [%s]", qPrintable(sinkId)); + + int index = -1; + + for (int i = 0; i < m_sampleSinkDevices.count(); i++) + { + qDebug("*** %s vs %s", qPrintable(m_sampleSinkDevices[i].m_deviceId), qPrintable(sinkId)); + + if(m_sampleSinkDevices[i].m_deviceId == sinkId) + { + index = i; + break; + } + } + + if(index == -1) + { + if(m_sampleSinkDevices.count() > 0) + { + index = 0; + } + else + { + return -1; + } + } + + qDebug() << "PluginManager::selectFirstSampleSink: m_sampleSink at index " << index + << " id: " << m_sampleSinkDevices[index].m_deviceId.toStdString().c_str() + << " ser: " << m_sampleSinkDevices[index].m_deviceSerial.toStdString().c_str() + << " seq: " << m_sampleSinkDevices[index].m_deviceSequence; + + deviceAPI->stopGeneration(); + deviceAPI->setSampleSinkPluginGUI(0); // this effectively destroys the previous GUI if it exists + + QWidget *gui; + PluginGUI *pluginGUI = m_sampleSinkDevices[index].m_plugin->createSampleSinkPluginGUI(m_sampleSinkDevices[index].m_deviceId, &gui, deviceAPI); + + // m_sampleSourcePluginGUI = pluginGUI; + deviceAPI->setSampleSinkSequence(m_sampleSinkDevices[index].m_deviceSequence); + deviceAPI->setSampleSinkId(m_sampleSinkDevices[index].m_deviceId); + deviceAPI->setSampleSinkSerial(m_sampleSinkDevices[index].m_deviceSerial); + deviceAPI->setSampleSinkPluginGUI(pluginGUI); + deviceAPI->setOutputGUI(gui, m_sampleSinkDevices[index].m_displayName); + + return index; +} + int PluginManager::selectSampleSourceBySerialOrSequence(const QString& sourceId, const QString& sourceSerial, int sourceSequence, DeviceSourceAPI *deviceAPI) { qDebug("PluginManager::selectSampleSourceBySequence by sequence: id: %s ser: %s seq: %d", qPrintable(sourceId), qPrintable(sourceSerial), sourceSequence); @@ -353,6 +549,80 @@ int PluginManager::selectSampleSourceBySerialOrSequence(const QString& sourceId, return index; } +int PluginManager::selectSampleSinkBySerialOrSequence(const QString& sinkId, const QString& sinkSerial, int sinkSequence, DeviceSinkAPI *deviceAPI) +{ + qDebug("PluginManager::selectSampleSinkBySerialOrSequence by sequence: id: %s ser: %s seq: %d", qPrintable(sinkId), qPrintable(sinkSerial), sinkSequence); + + int index = -1; + int index_matchingSequence = -1; + int index_firstOfKind = -1; + + for (int i = 0; i < m_sampleSinkDevices.count(); i++) + { + if (m_sampleSinkDevices[i].m_deviceId == sinkId) + { + index_firstOfKind = i; + + if (m_sampleSinkDevices[i].m_deviceSerial == sinkSerial) + { + index = i; // exact match + break; + } + + if (m_sampleSinkDevices[i].m_deviceSequence == sinkSequence) + { + index_matchingSequence = i; + } + } + } + + if(index == -1) // no exact match + { + if (index_matchingSequence == -1) // no matching sequence + { + if (index_firstOfKind == -1) // no matching device type + { + if(m_sampleSinkDevices.count() > 0) // take first if any + { + index = 0; + } + else + { + return -1; // return if no device attached + } + } + else + { + index = index_firstOfKind; // take first that matches device type + } + } + else + { + index = index_matchingSequence; // take the one that matches the sequence in the device type + } + } + + qDebug() << "PluginManager::selectSampleSinkBySerialOrSequence: m_sampleSink at index " << index + << " id: " << m_sampleSinkDevices[index].m_deviceId.toStdString().c_str() + << " ser: " << m_sampleSinkDevices[index].m_deviceSerial.toStdString().c_str() + << " seq: " << m_sampleSinkDevices[index].m_deviceSequence; + + deviceAPI->stopGeneration(); + deviceAPI->setSampleSinkPluginGUI(0); // this effectively destroys the previous GUI if it exists + + QWidget *gui; + PluginGUI *pluginGUI = m_sampleSinkDevices[index].m_plugin->createSampleSinkPluginGUI(m_sampleSinkDevices[index].m_deviceId, &gui, deviceAPI); + + // m_sampleSourcePluginGUI = pluginGUI; + deviceAPI->setSampleSinkSequence(m_sampleSinkDevices[index].m_deviceSequence); + deviceAPI->setSampleSinkId(m_sampleSinkDevices[index].m_deviceId); + deviceAPI->setSampleSinkSerial(m_sampleSinkDevices[index].m_deviceSerial); + deviceAPI->setSampleSinkPluginGUI(pluginGUI); + deviceAPI->setOutputGUI(gui, m_sampleSinkDevices[index].m_displayName); + + return index; +} + void PluginManager::selectSampleSourceByDevice(void *devicePtr, DeviceSourceAPI *deviceAPI) { SamplingDevice *sampleSourceDevice = (SamplingDevice *) devicePtr; @@ -376,6 +646,29 @@ void PluginManager::selectSampleSourceByDevice(void *devicePtr, DeviceSourceAPI deviceAPI->setInputGUI(gui, sampleSourceDevice->m_displayName); } +void PluginManager::selectSampleSinkByDevice(void *devicePtr, DeviceSinkAPI *deviceAPI) +{ + SamplingDevice *sampleSinkDevice = (SamplingDevice *) devicePtr; + + qDebug() << "PluginManager::selectSampleSinkByDevice: " + << " id: " << sampleSinkDevice->m_deviceId.toStdString().c_str() + << " ser: " << sampleSinkDevice->m_deviceSerial.toStdString().c_str() + << " seq: " << sampleSinkDevice->m_deviceSequence; + + deviceAPI->stopGeneration(); + deviceAPI->setSampleSinkPluginGUI(0); // this effectively destroys the previous GUI if it exists + + QWidget *gui; + PluginGUI *pluginGUI = sampleSinkDevice->m_plugin->createSampleSinkPluginGUI(sampleSinkDevice->m_deviceId, &gui, deviceAPI); + + // m_sampleSourcePluginGUI = pluginGUI; + deviceAPI->setSampleSinkSequence(sampleSinkDevice->m_deviceSequence); + deviceAPI->setSampleSinkId(sampleSinkDevice->m_deviceId); + deviceAPI->setSampleSinkSerial(sampleSinkDevice->m_deviceSerial); + deviceAPI->setSampleSinkPluginGUI(pluginGUI); + deviceAPI->setOutputGUI(gui, sampleSinkDevice->m_displayName); +} + void PluginManager::loadPlugins(const QDir& dir) { QDir pluginsDir(dir); @@ -428,6 +721,15 @@ void PluginManager::populateRxChannelComboBox(QComboBox *channels) } } +void PluginManager::populateTxChannelComboBox(QComboBox *channels) +{ + for(PluginAPI::ChannelRegistrations::iterator it = m_txChannelRegistrations.begin(); it != m_txChannelRegistrations.end(); ++it) + { + const PluginDescriptor& pluginDescipror = it->m_plugin->getPluginDescriptor(); + channels->addItem(pluginDescipror.displayedName); + } +} + void PluginManager::createRxChannelInstance(int channelPluginIndex, DeviceSourceAPI *deviceAPI) { if (channelPluginIndex < m_rxChannelRegistrations.size()) @@ -436,3 +738,12 @@ void PluginManager::createRxChannelInstance(int channelPluginIndex, DeviceSource pluginInterface->createRxChannel(m_rxChannelRegistrations[channelPluginIndex].m_channelName, deviceAPI); } } + +void PluginManager::createTxChannelInstance(int channelPluginIndex, DeviceSinkAPI *deviceAPI) +{ + if (channelPluginIndex < m_txChannelRegistrations.size()) + { + PluginInterface *pluginInterface = m_txChannelRegistrations[channelPluginIndex].m_plugin; + pluginInterface->createTxChannel(m_txChannelRegistrations[channelPluginIndex].m_channelName, deviceAPI); + } +} diff --git a/sdrbase/plugin/pluginmanager.h b/sdrbase/plugin/pluginmanager.h index bf33ccb59..afab1006e 100644 --- a/sdrbase/plugin/pluginmanager.h +++ b/sdrbase/plugin/pluginmanager.h @@ -14,6 +14,7 @@ class MainWindow; class Message; class MessageQueue; class DeviceSourceAPI; +class DeviceSinkAPI; class SDRANGEL_API PluginManager : public QObject { Q_OBJECT @@ -43,21 +44,36 @@ public: // Callbacks from the plugins void registerRxChannel(const QString& channelName, PluginInterface* plugin); void registerSampleSource(const QString& sourceName, PluginInterface* plugin); + void registerTxChannel(const QString& channelName, PluginInterface* plugin); + void registerSampleSink(const QString& sourceName, PluginInterface* plugin); PluginAPI::ChannelRegistrations *getRxChannelRegistrations() { return &m_rxChannelRegistrations; } + PluginAPI::ChannelRegistrations *getTxChannelRegistrations() { return &m_txChannelRegistrations; } void updateSampleSourceDevices(); void duplicateLocalSampleSourceDevices(uint deviceUID); void fillSampleSourceSelector(QComboBox* comboBox, uint deviceUID); + void updateSampleSinkDevices(); + void duplicateLocalSampleSinkDevices(uint deviceUID); + void fillSampleSinkSelector(QComboBox* comboBox, uint deviceUID); + int selectSampleSourceByIndex(int index, DeviceSourceAPI *deviceAPI); int selectFirstSampleSource(const QString& sourceId, DeviceSourceAPI *deviceAPI); int selectSampleSourceBySerialOrSequence(const QString& sourceId, const QString& sourceSerial, int sourceSequence, DeviceSourceAPI *deviceAPI); void selectSampleSourceByDevice(void *devicePtr, DeviceSourceAPI *deviceAPI); + int selectSampleSinkByIndex(int index, DeviceSinkAPI *deviceAPI); + int selectFirstSampleSink(const QString& sourceId, DeviceSinkAPI *deviceAPI); + int selectSampleSinkBySerialOrSequence(const QString& sinkId, const QString& sinkSerial, int sinkSequence, DeviceSinkAPI *deviceAPI); + void selectSampleSinkByDevice(void *devicePtr, DeviceSinkAPI *deviceAPI); + void populateRxChannelComboBox(QComboBox *channels); void createRxChannelInstance(int channelPluginIndex, DeviceSourceAPI *deviceAPI); + void populateTxChannelComboBox(QComboBox *channels); + void createTxChannelInstance(int channelPluginIndex, DeviceSinkAPI *deviceAPI); + private: struct SamplingDeviceRegistration { QString m_deviceId; @@ -100,10 +116,17 @@ private: SamplingDeviceRegistrations m_sampleSourceRegistrations; //!< Input source plugins (one per device kind) register here SamplingDevices m_sampleSourceDevices; //!< Instances of input sources present in the system + PluginAPI::ChannelRegistrations m_txChannelRegistrations; //!< Channel plugins register here + SamplingDeviceRegistrations m_sampleSinkRegistrations; //!< Output sink plugins (one per device kind) register here + SamplingDevices m_sampleSinkDevices; //!< Instances of output sinks present in the system + // "Local" sample source device IDs - static const QString m_sdrDaemonDeviceTypeID; //!< SDRdaemon source plugin ID - static const QString m_sdrDaemonFECDeviceTypeID; //!< SDRdaemon with FEC source plugin ID - static const QString m_fileSourceDeviceTypeID; //!< FileSource source plugin ID + static const QString m_sdrDaemonDeviceTypeID; //!< SDRdaemon source plugin ID + static const QString m_sdrDaemonFECDeviceTypeID; //!< SDRdaemon with FEC source plugin ID + static const QString m_fileSourceDeviceTypeID; //!< FileSource source plugin ID + + // "Local" sample sink device IDs + static const QString m_fileSinkDeviceTypeID; //!< FileSink sink plugin ID void loadPlugins(const QDir& dir);