mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-26 01:39:05 -05:00
Merge pull request #699 from srcejon/audio_input
Add audio input sample source
This commit is contained in:
commit
dc40755324
BIN
doc/img/AudioInput_plugin.png
Normal file
BIN
doc/img/AudioInput_plugin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
BIN
doc/img/AudioInput_plugin.xcf
Normal file
BIN
doc/img/AudioInput_plugin.xcf
Normal file
Binary file not shown.
@ -62,4 +62,5 @@ if(ENABLE_USRP AND UHD_FOUND)
|
||||
add_subdirectory(usrpinput)
|
||||
endif()
|
||||
|
||||
add_subdirectory(audioinput)
|
||||
add_subdirectory(kiwisdr)
|
57
plugins/samplesource/audioinput/CMakeLists.txt
Normal file
57
plugins/samplesource/audioinput/CMakeLists.txt
Normal file
@ -0,0 +1,57 @@
|
||||
project(audioinput)
|
||||
|
||||
set(audioinput_SOURCES
|
||||
audioinput.cpp
|
||||
audioinputplugin.cpp
|
||||
audioinputsettings.cpp
|
||||
audioinputwebapiadapter.cpp
|
||||
audioinputthread.cpp
|
||||
)
|
||||
|
||||
set(audioinput_HEADERS
|
||||
audioinput.h
|
||||
audioinputplugin.h
|
||||
audioinputsettings.h
|
||||
audioinputwebapiadapter.h
|
||||
audioinputthread.h
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||
)
|
||||
|
||||
if(NOT SERVER_MODE)
|
||||
set(audioinput_SOURCES
|
||||
${audioinput_SOURCES}
|
||||
audioinputgui.cpp
|
||||
audioinputgui.ui
|
||||
)
|
||||
set(audioinput_HEADERS
|
||||
${audioinput_HEADERS}
|
||||
audioinputgui.h
|
||||
)
|
||||
|
||||
set(TARGET_NAME inputaudio)
|
||||
set(TARGET_LIB "Qt5::Widgets")
|
||||
set(TARGET_LIB_GUI "sdrgui")
|
||||
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
|
||||
else()
|
||||
set(TARGET_NAME inputaudiosrv)
|
||||
set(TARGET_LIB "")
|
||||
set(TARGET_LIB_GUI "")
|
||||
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
|
||||
endif()
|
||||
|
||||
add_library(${TARGET_NAME} SHARED
|
||||
${audioinput_SOURCES}
|
||||
)
|
||||
|
||||
target_link_libraries(${TARGET_NAME}
|
||||
Qt5::Core
|
||||
${TARGET_LIB}
|
||||
sdrbase
|
||||
${TARGET_LIB_GUI}
|
||||
swagger
|
||||
)
|
||||
|
||||
install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})
|
525
plugins/samplesource/audioinput/audioinput.cpp
Normal file
525
plugins/samplesource/audioinput/audioinput.cpp
Normal file
@ -0,0 +1,525 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2015-2018 Edouard Griffiths, F4EXB //
|
||||
// Copyright (C) 2020 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/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QNetworkReply>
|
||||
#include <QBuffer>
|
||||
|
||||
#include "SWGDeviceSettings.h"
|
||||
#include "SWGDeviceState.h"
|
||||
|
||||
#include "dsp/dspcommands.h"
|
||||
#include "dsp/dspengine.h"
|
||||
#include "device/deviceapi.h"
|
||||
|
||||
#include "audioinput.h"
|
||||
#include "audioinputthread.h"
|
||||
|
||||
MESSAGE_CLASS_DEFINITION(AudioInputSource::AudioInput::MsgConfigureAudioInput, Message)
|
||||
MESSAGE_CLASS_DEFINITION(AudioInputSource::AudioInput::MsgStartStop, Message)
|
||||
|
||||
namespace AudioInputSource {
|
||||
|
||||
AudioInput::AudioInput(DeviceAPI *deviceAPI) :
|
||||
m_deviceAPI(deviceAPI),
|
||||
m_settings(),
|
||||
m_thread(nullptr),
|
||||
m_deviceDescription("AudioInput"),
|
||||
m_running(false)
|
||||
{
|
||||
m_fifo.setSize(20*AudioInputThread::m_convBufSamples);
|
||||
openDevice();
|
||||
m_deviceAPI->setNbSourceStreams(1);
|
||||
m_networkManager = new QNetworkAccessManager();
|
||||
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||
}
|
||||
|
||||
AudioInput::~AudioInput()
|
||||
{
|
||||
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||
delete m_networkManager;
|
||||
|
||||
if (m_running) {
|
||||
stop();
|
||||
}
|
||||
|
||||
closeDevice();
|
||||
}
|
||||
|
||||
void AudioInput::destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
bool AudioInput::openDevice()
|
||||
{
|
||||
if (!openAudioDevice(m_settings.m_deviceName, m_settings.m_sampleRate))
|
||||
{
|
||||
qCritical("AudioInput::openDevice: could not open audio source");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioInput::openAudioDevice(QString deviceName, qint32 sampleRate)
|
||||
{
|
||||
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
||||
const QList<QAudioDeviceInfo>& audioList = audioDeviceManager->getInputDevices();
|
||||
|
||||
for (const auto &itAudio : audioList)
|
||||
{
|
||||
if (AudioInputSettings::getFullDeviceName(itAudio) == deviceName)
|
||||
{
|
||||
// FIXME: getInputDeviceIndex needs a realm parameter (itAudio.realm())
|
||||
int deviceIndex = audioDeviceManager->getInputDeviceIndex(itAudio.deviceName());
|
||||
m_audioInput.start(deviceIndex, sampleRate);
|
||||
m_audioInput.addFifo(&m_fifo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AudioInput::init()
|
||||
{
|
||||
applySettings(m_settings, true);
|
||||
}
|
||||
|
||||
bool AudioInput::start()
|
||||
{
|
||||
qDebug() << "AudioInput::start";
|
||||
|
||||
if (m_running) stop();
|
||||
|
||||
if(!m_sampleFifo.setSize(96000*4))
|
||||
{
|
||||
qCritical("Could not allocate SampleFifo");
|
||||
return false;
|
||||
}
|
||||
|
||||
applySettings(m_settings, true, true);
|
||||
|
||||
m_thread = new AudioInputThread(&m_sampleFifo, &m_fifo);
|
||||
m_thread->setLog2Decimation(m_settings.m_log2Decim);
|
||||
m_thread->setIQMapping(m_settings.m_iqMapping);
|
||||
m_thread->startWork();
|
||||
|
||||
|
||||
qDebug("AudioInput::started");
|
||||
m_running = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AudioInput::closeDevice()
|
||||
{
|
||||
m_audioInput.removeFifo(&m_fifo);
|
||||
m_audioInput.stop();
|
||||
}
|
||||
|
||||
void AudioInput::stop()
|
||||
{
|
||||
if (m_thread)
|
||||
{
|
||||
m_thread->stopWork();
|
||||
// wait for thread to quit ?
|
||||
delete m_thread;
|
||||
m_thread = nullptr;
|
||||
}
|
||||
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
QByteArray AudioInput::serialize() const
|
||||
{
|
||||
return m_settings.serialize();
|
||||
}
|
||||
|
||||
bool AudioInput::deserialize(const QByteArray& data)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
if (!m_settings.deserialize(data))
|
||||
{
|
||||
m_settings.resetToDefaults();
|
||||
success = false;
|
||||
}
|
||||
|
||||
MsgConfigureAudioInput* message = MsgConfigureAudioInput::create(m_settings, true);
|
||||
m_inputMessageQueue.push(message);
|
||||
|
||||
if (m_guiMessageQueue)
|
||||
{
|
||||
MsgConfigureAudioInput* messageToGUI = MsgConfigureAudioInput::create(m_settings, true);
|
||||
m_guiMessageQueue->push(messageToGUI);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
const QString& AudioInput::getDeviceDescription() const
|
||||
{
|
||||
return m_deviceDescription;
|
||||
}
|
||||
|
||||
int AudioInput::getSampleRate() const
|
||||
{
|
||||
return m_settings.m_sampleRate/(1<<m_settings.m_log2Decim);
|
||||
}
|
||||
|
||||
quint64 AudioInput::getCenterFrequency() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AudioInput::setCenterFrequency(qint64 centerFrequency)
|
||||
{
|
||||
}
|
||||
|
||||
bool AudioInput::handleMessage(const Message& message)
|
||||
{
|
||||
if(MsgConfigureAudioInput::match(message))
|
||||
{
|
||||
qDebug() << "AudioInput::handleMessage: MsgConfigureAudioInput";
|
||||
MsgConfigureAudioInput& conf = (MsgConfigureAudioInput&) message;
|
||||
applySettings(conf.getSettings(), conf.getForce());
|
||||
return true;
|
||||
}
|
||||
else if (MsgStartStop::match(message))
|
||||
{
|
||||
MsgStartStop& cmd = (MsgStartStop&) message;
|
||||
qDebug() << "AudioInput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
|
||||
|
||||
if (cmd.getStartStop())
|
||||
{
|
||||
if (m_deviceAPI->initDeviceEngine())
|
||||
{
|
||||
m_deviceAPI->startDeviceEngine();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_deviceAPI->stopDeviceEngine();
|
||||
}
|
||||
|
||||
if (m_settings.m_useReverseAPI) {
|
||||
webapiReverseSendStartStop(cmd.getStartStop());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioInput::applySettings(const AudioInputSettings& settings, bool force, bool starting)
|
||||
{
|
||||
bool forwardChange = false;
|
||||
QList<QString> reverseAPIKeys;
|
||||
|
||||
if ((m_settings.m_deviceName != settings.m_deviceName)
|
||||
|| (m_settings.m_sampleRate != settings.m_sampleRate) || force)
|
||||
{
|
||||
// Don't call openAudioDevice if called from start(), otherwise ::AudioInput
|
||||
// will be created on wrong thread and we'll crash after ::AudioInput::stop calls delete
|
||||
if (!starting)
|
||||
{
|
||||
closeDevice();
|
||||
if (openAudioDevice(settings.m_deviceName, settings.m_sampleRate))
|
||||
qDebug() << "AudioInput::applySettings: opened device " << settings.m_deviceName << " with sample rate " << m_audioInput.getRate();
|
||||
else
|
||||
qCritical() << "AudioInput::applySettings: failed to open device " << settings.m_deviceName;
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_deviceName != settings.m_deviceName) || force)
|
||||
{
|
||||
reverseAPIKeys.append("device");
|
||||
}
|
||||
|
||||
if ((m_settings.m_sampleRate != settings.m_sampleRate) || force)
|
||||
{
|
||||
reverseAPIKeys.append("sampleRate");
|
||||
forwardChange = true;
|
||||
}
|
||||
|
||||
if ((m_settings.m_volume != settings.m_volume) || force)
|
||||
{
|
||||
reverseAPIKeys.append("volume");
|
||||
m_audioInput.setVolume(settings.m_volume);
|
||||
qDebug() << "AudioInput::applySettings: set volume to " << settings.m_volume;
|
||||
}
|
||||
|
||||
if ((m_settings.m_log2Decim != settings.m_log2Decim) || force)
|
||||
{
|
||||
reverseAPIKeys.append("log2Decim");
|
||||
forwardChange = true;
|
||||
|
||||
if (m_thread)
|
||||
{
|
||||
m_thread->setLog2Decimation(settings.m_log2Decim);
|
||||
qDebug() << "AudioInput::applySettings: set decimation to " << (1<<settings.m_log2Decim);
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_iqMapping != settings.m_iqMapping) || force)
|
||||
{
|
||||
reverseAPIKeys.append("iqMapping");
|
||||
if (m_thread)
|
||||
m_thread->setIQMapping(settings.m_iqMapping);
|
||||
}
|
||||
|
||||
if (settings.m_useReverseAPI)
|
||||
{
|
||||
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
|
||||
(m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) ||
|
||||
(m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) ||
|
||||
(m_settings.m_reverseAPIDeviceIndex != settings.m_reverseAPIDeviceIndex);
|
||||
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
|
||||
}
|
||||
|
||||
m_settings = settings;
|
||||
|
||||
if (forwardChange)
|
||||
{
|
||||
DSPSignalNotification *notif = new DSPSignalNotification(m_settings.m_sampleRate/(1<<m_settings.m_log2Decim), 0);
|
||||
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
|
||||
}
|
||||
}
|
||||
|
||||
int AudioInput::webapiRunGet(
|
||||
SWGSDRangel::SWGDeviceState& response,
|
||||
QString& errorMessage)
|
||||
{
|
||||
(void) errorMessage;
|
||||
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
|
||||
return 200;
|
||||
}
|
||||
|
||||
int AudioInput::webapiRun(
|
||||
bool run,
|
||||
SWGSDRangel::SWGDeviceState& response,
|
||||
QString& errorMessage)
|
||||
{
|
||||
(void) errorMessage;
|
||||
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
|
||||
MsgStartStop *message = MsgStartStop::create(run);
|
||||
m_inputMessageQueue.push(message);
|
||||
|
||||
if (m_guiMessageQueue) // forward to GUI if any
|
||||
{
|
||||
MsgStartStop *msgToGUI = MsgStartStop::create(run);
|
||||
m_guiMessageQueue->push(msgToGUI);
|
||||
}
|
||||
|
||||
return 200;
|
||||
}
|
||||
|
||||
int AudioInput::webapiSettingsGet(
|
||||
SWGSDRangel::SWGDeviceSettings& response,
|
||||
QString& errorMessage)
|
||||
{
|
||||
(void) errorMessage;
|
||||
response.setAudioInputSettings(new SWGSDRangel::SWGAudioInputSettings());
|
||||
response.getAudioInputSettings()->init();
|
||||
webapiFormatDeviceSettings(response, m_settings);
|
||||
|
||||
return 200;
|
||||
}
|
||||
|
||||
int AudioInput::webapiSettingsPutPatch(
|
||||
bool force,
|
||||
const QStringList& deviceSettingsKeys,
|
||||
SWGSDRangel::SWGDeviceSettings& response, // query + response
|
||||
QString& errorMessage)
|
||||
{
|
||||
(void) errorMessage;
|
||||
AudioInputSettings settings = m_settings;
|
||||
webapiUpdateDeviceSettings(settings, deviceSettingsKeys, response);
|
||||
|
||||
MsgConfigureAudioInput *msg = MsgConfigureAudioInput::create(settings, force);
|
||||
m_inputMessageQueue.push(msg);
|
||||
|
||||
if (m_guiMessageQueue) // forward to GUI if any
|
||||
{
|
||||
MsgConfigureAudioInput *msgToGUI = MsgConfigureAudioInput::create(settings, force);
|
||||
m_guiMessageQueue->push(msgToGUI);
|
||||
}
|
||||
|
||||
webapiFormatDeviceSettings(response, settings);
|
||||
return 200;
|
||||
}
|
||||
|
||||
void AudioInput::webapiUpdateDeviceSettings(
|
||||
AudioInputSettings& settings,
|
||||
const QStringList& deviceSettingsKeys,
|
||||
SWGSDRangel::SWGDeviceSettings& response)
|
||||
{
|
||||
if (deviceSettingsKeys.contains("device")) {
|
||||
settings.m_deviceName = *response.getAudioInputSettings()->getDevice();
|
||||
}
|
||||
if (deviceSettingsKeys.contains("devSampleRate")) {
|
||||
settings.m_sampleRate = response.getAudioInputSettings()->getDevSampleRate();
|
||||
}
|
||||
if (deviceSettingsKeys.contains("volume")) {
|
||||
settings.m_volume = response.getAudioInputSettings()->getVolume();
|
||||
}
|
||||
if (deviceSettingsKeys.contains("log2Decim")) {
|
||||
settings.m_log2Decim = response.getAudioInputSettings()->getLog2Decim();
|
||||
}
|
||||
if (deviceSettingsKeys.contains("iqMapping")) {
|
||||
settings.m_iqMapping = (AudioInputSettings::IQMapping)response.getAudioInputSettings()->getIqMapping();
|
||||
}
|
||||
if (deviceSettingsKeys.contains("useReverseAPI")) {
|
||||
settings.m_useReverseAPI = response.getAudioInputSettings()->getUseReverseApi() != 0;
|
||||
}
|
||||
if (deviceSettingsKeys.contains("reverseAPIAddress")) {
|
||||
settings.m_reverseAPIAddress = *response.getAudioInputSettings()->getReverseApiAddress();
|
||||
}
|
||||
if (deviceSettingsKeys.contains("reverseAPIPort")) {
|
||||
settings.m_reverseAPIPort = response.getAudioInputSettings()->getReverseApiPort();
|
||||
}
|
||||
if (deviceSettingsKeys.contains("reverseAPIDeviceIndex")) {
|
||||
settings.m_reverseAPIDeviceIndex = response.getAudioInputSettings()->getReverseApiDeviceIndex();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioInput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const AudioInputSettings& settings)
|
||||
{
|
||||
response.getAudioInputSettings()->setDevice(new QString(settings.m_deviceName));
|
||||
response.getAudioInputSettings()->setDevSampleRate(settings.m_sampleRate);
|
||||
response.getAudioInputSettings()->setVolume(settings.m_volume);
|
||||
response.getAudioInputSettings()->setLog2Decim(settings.m_log2Decim);
|
||||
response.getAudioInputSettings()->setIqMapping((int)settings.m_iqMapping);
|
||||
|
||||
response.getAudioInputSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
|
||||
|
||||
if (response.getAudioInputSettings()->getReverseApiAddress()) {
|
||||
*response.getAudioInputSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
|
||||
} else {
|
||||
response.getAudioInputSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
|
||||
}
|
||||
|
||||
response.getAudioInputSettings()->setReverseApiPort(settings.m_reverseAPIPort);
|
||||
response.getAudioInputSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
|
||||
}
|
||||
|
||||
void AudioInput::webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const AudioInputSettings& settings, bool force)
|
||||
{
|
||||
SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings();
|
||||
swgDeviceSettings->setDirection(0); // single Rx
|
||||
swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
|
||||
swgDeviceSettings->setDeviceHwType(new QString("AudioInput"));
|
||||
swgDeviceSettings->setAudioInputSettings(new SWGSDRangel::SWGAudioInputSettings());
|
||||
SWGSDRangel::SWGAudioInputSettings *swgAudioInputSettings = swgDeviceSettings->getAudioInputSettings();
|
||||
|
||||
// transfer data that has been modified. When force is on transfer all data except reverse API data
|
||||
|
||||
if (deviceSettingsKeys.contains("device") || force) {
|
||||
swgAudioInputSettings->setDevice(new QString(settings.m_deviceName));
|
||||
}
|
||||
if (deviceSettingsKeys.contains("devSampleRate") || force) {
|
||||
swgAudioInputSettings->setDevSampleRate(settings.m_sampleRate);
|
||||
}
|
||||
if (deviceSettingsKeys.contains("volume") || force) {
|
||||
swgAudioInputSettings->setVolume(settings.m_volume);
|
||||
}
|
||||
if (deviceSettingsKeys.contains("log2Decim") || force) {
|
||||
swgAudioInputSettings->setLog2Decim(settings.m_log2Decim);
|
||||
}
|
||||
if (deviceSettingsKeys.contains("iqMapping") || force) {
|
||||
swgAudioInputSettings->setIqMapping(settings.m_iqMapping);
|
||||
}
|
||||
|
||||
QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings")
|
||||
.arg(settings.m_reverseAPIAddress)
|
||||
.arg(settings.m_reverseAPIPort)
|
||||
.arg(settings.m_reverseAPIDeviceIndex);
|
||||
m_networkRequest.setUrl(QUrl(deviceSettingsURL));
|
||||
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
QBuffer *buffer = new QBuffer();
|
||||
buffer->open((QBuffer::ReadWrite));
|
||||
buffer->write(swgDeviceSettings->asJson().toUtf8());
|
||||
buffer->seek(0);
|
||||
|
||||
// Always use PATCH to avoid passing reverse API settings
|
||||
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
|
||||
buffer->setParent(reply);
|
||||
|
||||
delete swgDeviceSettings;
|
||||
}
|
||||
|
||||
void AudioInput::webapiReverseSendStartStop(bool start)
|
||||
{
|
||||
SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings();
|
||||
swgDeviceSettings->setDirection(0); // single Rx
|
||||
swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
|
||||
swgDeviceSettings->setDeviceHwType(new QString("AudioInput"));
|
||||
|
||||
QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/run")
|
||||
.arg(m_settings.m_reverseAPIAddress)
|
||||
.arg(m_settings.m_reverseAPIPort)
|
||||
.arg(m_settings.m_reverseAPIDeviceIndex);
|
||||
m_networkRequest.setUrl(QUrl(deviceSettingsURL));
|
||||
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
QBuffer *buffer = new QBuffer();
|
||||
buffer->open((QBuffer::ReadWrite));
|
||||
buffer->write(swgDeviceSettings->asJson().toUtf8());
|
||||
buffer->seek(0);
|
||||
QNetworkReply *reply;
|
||||
|
||||
if (start) {
|
||||
reply = m_networkManager->sendCustomRequest(m_networkRequest, "POST", buffer);
|
||||
} else {
|
||||
reply = m_networkManager->sendCustomRequest(m_networkRequest, "DELETE", buffer);
|
||||
}
|
||||
|
||||
buffer->setParent(reply);
|
||||
delete swgDeviceSettings;
|
||||
}
|
||||
|
||||
void AudioInput::networkManagerFinished(QNetworkReply *reply)
|
||||
{
|
||||
QNetworkReply::NetworkError replyError = reply->error();
|
||||
|
||||
if (replyError)
|
||||
{
|
||||
qWarning() << "AudioInput::networkManagerFinished:"
|
||||
<< " error(" << (int) replyError
|
||||
<< "): " << replyError
|
||||
<< ": " << reply->errorString();
|
||||
}
|
||||
else
|
||||
{
|
||||
QString answer = reply->readAll();
|
||||
answer.chop(1); // remove last \n
|
||||
qDebug("AudioInput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
}
|
161
plugins/samplesource/audioinput/audioinput.h
Normal file
161
plugins/samplesource/audioinput/audioinput.h
Normal file
@ -0,0 +1,161 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2015-2018 Edouard Griffiths, F4EXB //
|
||||
// Copyright (C) 2020 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/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_AUDIOINPUT_H
|
||||
#define INCLUDE_AUDIOINPUT_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
#include <QNetworkRequest>
|
||||
|
||||
#include "dsp/devicesamplesource.h"
|
||||
#include "audio/audioinput.h"
|
||||
#include "audio/audiofifo.h"
|
||||
|
||||
#include "audioinputsettings.h"
|
||||
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
class DeviceAPI;
|
||||
class AudioInputThread;
|
||||
|
||||
// AudioInput is used in sdrbase/audio/audioinput.h
|
||||
namespace AudioInputSource {
|
||||
|
||||
class AudioInput : public DeviceSampleSource {
|
||||
Q_OBJECT
|
||||
public:
|
||||
class MsgConfigureAudioInput : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
const AudioInputSettings& getSettings() const { return m_settings; }
|
||||
bool getForce() const { return m_force; }
|
||||
|
||||
static MsgConfigureAudioInput* create(const AudioInputSettings& settings, bool force)
|
||||
{
|
||||
return new MsgConfigureAudioInput(settings, force);
|
||||
}
|
||||
|
||||
private:
|
||||
AudioInputSettings m_settings;
|
||||
bool m_force;
|
||||
|
||||
MsgConfigureAudioInput(const AudioInputSettings& settings, bool force) :
|
||||
Message(),
|
||||
m_settings(settings),
|
||||
m_force(force)
|
||||
{ }
|
||||
};
|
||||
|
||||
class MsgStartStop : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
bool getStartStop() const { return m_startStop; }
|
||||
|
||||
static MsgStartStop* create(bool startStop) {
|
||||
return new MsgStartStop(startStop);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool m_startStop;
|
||||
|
||||
MsgStartStop(bool startStop) :
|
||||
Message(),
|
||||
m_startStop(startStop)
|
||||
{ }
|
||||
};
|
||||
|
||||
AudioInput(DeviceAPI *deviceAPI);
|
||||
virtual ~AudioInput();
|
||||
virtual void destroy();
|
||||
|
||||
virtual void init();
|
||||
virtual bool start();
|
||||
virtual void stop();
|
||||
|
||||
virtual QByteArray serialize() const;
|
||||
virtual bool deserialize(const QByteArray& data);
|
||||
|
||||
virtual void setMessageQueueToGUI(MessageQueue *queue) { m_guiMessageQueue = queue; }
|
||||
virtual const QString& getDeviceDescription() const;
|
||||
virtual int getSampleRate() const;
|
||||
virtual void setSampleRate(int sampleRate) { (void) sampleRate; }
|
||||
virtual quint64 getCenterFrequency() const;
|
||||
virtual void setCenterFrequency(qint64 centerFrequency);
|
||||
|
||||
virtual bool handleMessage(const Message& message);
|
||||
|
||||
virtual int webapiSettingsGet(
|
||||
SWGSDRangel::SWGDeviceSettings& response,
|
||||
QString& errorMessage);
|
||||
|
||||
virtual int webapiSettingsPutPatch(
|
||||
bool force,
|
||||
const QStringList& deviceSettingsKeys,
|
||||
SWGSDRangel::SWGDeviceSettings& response, // query + response
|
||||
QString& errorMessage);
|
||||
|
||||
virtual int webapiRunGet(
|
||||
SWGSDRangel::SWGDeviceState& response,
|
||||
QString& errorMessage);
|
||||
|
||||
virtual int webapiRun(
|
||||
bool run,
|
||||
SWGSDRangel::SWGDeviceState& response,
|
||||
QString& errorMessage);
|
||||
|
||||
static void webapiFormatDeviceSettings(
|
||||
SWGSDRangel::SWGDeviceSettings& response,
|
||||
const AudioInputSettings& settings);
|
||||
|
||||
static void webapiUpdateDeviceSettings(
|
||||
AudioInputSettings& settings,
|
||||
const QStringList& deviceSettingsKeys,
|
||||
SWGSDRangel::SWGDeviceSettings& response);
|
||||
|
||||
private:
|
||||
DeviceAPI *m_deviceAPI;
|
||||
::AudioInput m_audioInput;
|
||||
AudioFifo m_fifo;
|
||||
QMutex m_mutex;
|
||||
AudioInputSettings m_settings;
|
||||
AudioInputThread* m_thread;
|
||||
QString m_deviceDescription;
|
||||
bool m_running;
|
||||
QNetworkAccessManager *m_networkManager;
|
||||
QNetworkRequest m_networkRequest;
|
||||
|
||||
bool openDevice();
|
||||
void closeDevice();
|
||||
bool openAudioDevice(QString deviceName, int sampleRate);
|
||||
void applySettings(const AudioInputSettings& settings, bool force, bool starting=false);
|
||||
|
||||
void webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const AudioInputSettings& settings, bool force);
|
||||
void webapiReverseSendStartStop(bool start);
|
||||
|
||||
private slots:
|
||||
void networkManagerFinished(QNetworkReply *reply);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // INCLUDE_AUDIOINPUT_H
|
304
plugins/samplesource/audioinput/audioinputgui.cpp
Normal file
304
plugins/samplesource/audioinput/audioinputgui.cpp
Normal file
@ -0,0 +1,304 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2015 Edouard Griffiths, F4EXB //
|
||||
// Copyright (C) 2020 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/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
|
||||
#include "ui_audioinputgui.h"
|
||||
#include "gui/colormapper.h"
|
||||
#include "gui/glspectrum.h"
|
||||
#include "gui/crightclickenabler.h"
|
||||
#include "gui/basicdevicesettingsdialog.h"
|
||||
#include "dsp/dspengine.h"
|
||||
#include "dsp/dspcommands.h"
|
||||
#include "audioinputgui.h"
|
||||
|
||||
#include "device/deviceapi.h"
|
||||
#include "device/deviceuiset.h"
|
||||
|
||||
AudioInputGui::AudioInputGui(DeviceUISet *deviceUISet, QWidget* parent) :
|
||||
DeviceGUI(parent),
|
||||
ui(new Ui::AudioInputGui),
|
||||
m_deviceUISet(deviceUISet),
|
||||
m_forceSettings(true),
|
||||
m_settings(),
|
||||
m_sampleSource(NULL)
|
||||
{
|
||||
m_sampleSource = (AudioInputSource::AudioInput*) m_deviceUISet->m_deviceAPI->getSampleSource();
|
||||
|
||||
ui->setupUi(this);
|
||||
|
||||
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
|
||||
|
||||
CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop);
|
||||
connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &)));
|
||||
|
||||
displaySettings();
|
||||
|
||||
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
|
||||
m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue);
|
||||
}
|
||||
|
||||
AudioInputGui::~AudioInputGui()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void AudioInputGui::destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
void AudioInputGui::resetToDefaults()
|
||||
{
|
||||
m_settings.resetToDefaults();
|
||||
displaySettings();
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
QByteArray AudioInputGui::serialize() const
|
||||
{
|
||||
return m_settings.serialize();
|
||||
}
|
||||
|
||||
bool AudioInputGui::deserialize(const QByteArray& data)
|
||||
{
|
||||
if(m_settings.deserialize(data))
|
||||
{
|
||||
displaySettings();
|
||||
m_forceSettings = true;
|
||||
sendSettings();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
resetToDefaults();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioInputGui::handleMessage(const Message& message)
|
||||
{
|
||||
if (AudioInputSource::AudioInput::MsgConfigureAudioInput::match(message))
|
||||
{
|
||||
const AudioInputSource::AudioInput::MsgConfigureAudioInput& cfg = (AudioInputSource::AudioInput::MsgConfigureAudioInput&) message;
|
||||
m_settings = cfg.getSettings();
|
||||
blockApplySettings(true);
|
||||
displaySettings();
|
||||
blockApplySettings(false);
|
||||
return true;
|
||||
}
|
||||
else if (AudioInputSource::AudioInput::MsgStartStop::match(message))
|
||||
{
|
||||
AudioInputSource::AudioInput::MsgStartStop& notif = (AudioInputSource::AudioInput::MsgStartStop&) message;
|
||||
blockApplySettings(true);
|
||||
ui->startStop->setChecked(notif.getStartStop());
|
||||
blockApplySettings(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioInputGui::handleInputMessages()
|
||||
{
|
||||
Message* message;
|
||||
|
||||
while ((message = m_inputMessageQueue.pop()) != 0)
|
||||
{
|
||||
qDebug("AudioInputGui::handleInputMessages: message: %s", message->getIdentifier());
|
||||
|
||||
if (DSPSignalNotification::match(*message))
|
||||
{
|
||||
DSPSignalNotification* notif = (DSPSignalNotification*) message;
|
||||
m_sampleRate = notif->getSampleRate();
|
||||
qDebug("AudioInputGui::handleInputMessages: DSPSignalNotification: SampleRate: %d", notif->getSampleRate());
|
||||
updateSampleRateAndFrequency();
|
||||
|
||||
delete message;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (handleMessage(*message))
|
||||
{
|
||||
delete message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioInputGui::updateSampleRateAndFrequency()
|
||||
{
|
||||
/*
|
||||
// Can't seem to get main spectrum to only display real part for mono/I-channel only
|
||||
if (m_settings.m_iqMapping <= AudioInputSettings::IQMapping::R)
|
||||
{
|
||||
m_deviceUISet->getSpectrum()->setSampleRate(m_sampleRate / 2);
|
||||
m_deviceUISet->getSpectrum()->setCenterFrequency(m_sampleRate / 4);
|
||||
m_deviceUISet->getSpectrum()->setSsbSpectrum(true);
|
||||
m_deviceUISet->getSpectrum()->setLsbDisplay(false);
|
||||
}
|
||||
else
|
||||
*/
|
||||
{
|
||||
m_deviceUISet->getSpectrum()->setSampleRate(m_sampleRate);
|
||||
m_deviceUISet->getSpectrum()->setCenterFrequency(0);
|
||||
m_deviceUISet->getSpectrum()->setSsbSpectrum(false);
|
||||
m_deviceUISet->getSpectrum()->setLsbDisplay(false);
|
||||
}
|
||||
ui->deviceRateText->setText(tr("%1k").arg((float)m_sampleRate / 1000));
|
||||
}
|
||||
|
||||
void AudioInputGui::refreshDeviceList()
|
||||
{
|
||||
ui->device->blockSignals(true);
|
||||
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
||||
const QList<QAudioDeviceInfo>& audioList = audioDeviceManager->getInputDevices();
|
||||
|
||||
ui->device->clear();
|
||||
for (const auto &itAudio : audioList)
|
||||
{
|
||||
ui->device->addItem(AudioInputSettings::getFullDeviceName(itAudio));
|
||||
}
|
||||
ui->device->blockSignals(false);
|
||||
}
|
||||
|
||||
void AudioInputGui::refreshSampleRates(QString deviceName)
|
||||
{
|
||||
ui->sampleRate->blockSignals(true);
|
||||
ui->sampleRate->clear();
|
||||
const auto deviceInfos = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
|
||||
for (const QAudioDeviceInfo &deviceInfo : deviceInfos)
|
||||
{
|
||||
if (deviceName == AudioInputSettings::getFullDeviceName(deviceInfo))
|
||||
{
|
||||
QList<int> sampleRates = deviceInfo.supportedSampleRates();
|
||||
for(int i = 0; i < sampleRates.size(); ++i)
|
||||
{
|
||||
ui->sampleRate->addItem(QString("%1").arg(sampleRates[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
ui->sampleRate->blockSignals(false);
|
||||
|
||||
int index = ui->sampleRate->findText(QString("%1").arg(m_settings.m_sampleRate));
|
||||
if (index >= 0)
|
||||
ui->sampleRate->setCurrentIndex(index);
|
||||
else
|
||||
ui->sampleRate->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
void AudioInputGui::displaySettings()
|
||||
{
|
||||
refreshDeviceList();
|
||||
int index = ui->device->findText(m_settings.m_deviceName);
|
||||
if (index >= 0)
|
||||
ui->device->setCurrentIndex(index);
|
||||
else
|
||||
ui->device->setCurrentIndex(0);
|
||||
ui->decim->setCurrentIndex(m_settings.m_log2Decim);
|
||||
ui->volume->setValue((int)(m_settings.m_volume*10.0f));
|
||||
ui->volumeText->setText(QString("%1").arg(m_settings.m_volume, 3, 'f', 1));
|
||||
ui->channels->setCurrentIndex((int)m_settings.m_iqMapping);
|
||||
refreshSampleRates(ui->device->currentText());
|
||||
}
|
||||
|
||||
void AudioInputGui::on_device_currentIndexChanged(int index)
|
||||
{
|
||||
m_settings.m_deviceName = ui->device->currentText();
|
||||
refreshSampleRates(m_settings.m_deviceName);
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void AudioInputGui::on_sampleRate_currentIndexChanged(int index)
|
||||
{
|
||||
m_settings.m_sampleRate = ui->sampleRate->currentText().toInt();
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void AudioInputGui::on_decim_currentIndexChanged(int index)
|
||||
{
|
||||
if ((index < 0) || (index > 6)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_settings.m_log2Decim = index;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void AudioInputGui::on_volume_valueChanged(int value)
|
||||
{
|
||||
m_settings.m_volume = value/10.0f;
|
||||
ui->volumeText->setText(QString("%1").arg(m_settings.m_volume, 3, 'f', 1));
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void AudioInputGui::on_channels_currentIndexChanged(int index)
|
||||
{
|
||||
m_settings.m_iqMapping = (AudioInputSettings::IQMapping)index;
|
||||
updateSampleRateAndFrequency();
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void AudioInputGui::on_startStop_toggled(bool checked)
|
||||
{
|
||||
if (m_doApplySettings)
|
||||
{
|
||||
AudioInputSource::AudioInput::MsgStartStop *message = AudioInputSource::AudioInput::MsgStartStop::create(checked);
|
||||
m_sampleSource->getInputMessageQueue()->push(message);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioInputGui::sendSettings()
|
||||
{
|
||||
if(!m_updateTimer.isActive())
|
||||
m_updateTimer.start(100);
|
||||
}
|
||||
|
||||
void AudioInputGui::updateHardware()
|
||||
{
|
||||
if (m_doApplySettings)
|
||||
{
|
||||
AudioInputSource::AudioInput::MsgConfigureAudioInput* message = AudioInputSource::AudioInput::MsgConfigureAudioInput::create(m_settings, m_forceSettings);
|
||||
m_sampleSource->getInputMessageQueue()->push(message);
|
||||
m_forceSettings = false;
|
||||
m_updateTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioInputGui::openDeviceSettingsDialog(const QPoint& p)
|
||||
{
|
||||
BasicDeviceSettingsDialog dialog(this);
|
||||
dialog.setUseReverseAPI(m_settings.m_useReverseAPI);
|
||||
dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress);
|
||||
dialog.setReverseAPIPort(m_settings.m_reverseAPIPort);
|
||||
dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex);
|
||||
|
||||
dialog.move(p);
|
||||
dialog.exec();
|
||||
|
||||
m_settings.m_useReverseAPI = dialog.useReverseAPI();
|
||||
m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress();
|
||||
m_settings.m_reverseAPIPort = dialog.getReverseAPIPort();
|
||||
m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex();
|
||||
|
||||
sendSettings();
|
||||
}
|
83
plugins/samplesource/audioinput/audioinputgui.h
Normal file
83
plugins/samplesource/audioinput/audioinputgui.h
Normal file
@ -0,0 +1,83 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2015 Edouard Griffiths, F4EXB //
|
||||
// Copyright (C) 2020 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/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_AUDIOINPUTGUI_H
|
||||
#define INCLUDE_AUDIOINPUTGUI_H
|
||||
|
||||
#include <device/devicegui.h>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
#include "util/messagequeue.h"
|
||||
|
||||
#include "audioinput.h"
|
||||
|
||||
class QWidget;
|
||||
class DeviceUISet;
|
||||
|
||||
namespace Ui {
|
||||
class AudioInputGui;
|
||||
}
|
||||
|
||||
class AudioInputGui : public DeviceGUI {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AudioInputGui(DeviceUISet *deviceUISet, QWidget* parent = 0);
|
||||
virtual ~AudioInputGui();
|
||||
virtual void destroy();
|
||||
|
||||
void resetToDefaults();
|
||||
QByteArray serialize() const;
|
||||
bool deserialize(const QByteArray& data);
|
||||
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||
|
||||
private:
|
||||
Ui::AudioInputGui* ui;
|
||||
|
||||
DeviceUISet* m_deviceUISet;
|
||||
bool m_doApplySettings;
|
||||
bool m_forceSettings;
|
||||
AudioInputSettings m_settings;
|
||||
QTimer m_updateTimer;
|
||||
DeviceSampleSource* m_sampleSource;
|
||||
int m_sampleRate;
|
||||
|
||||
MessageQueue m_inputMessageQueue;
|
||||
|
||||
void blockApplySettings(bool block) { m_doApplySettings = !block; }
|
||||
void refreshDeviceList();
|
||||
void refreshSampleRates(QString deviceName);
|
||||
void displaySettings();
|
||||
void sendSettings();
|
||||
void updateSampleRateAndFrequency();
|
||||
bool handleMessage(const Message& message);
|
||||
|
||||
private slots:
|
||||
void handleInputMessages();
|
||||
void on_device_currentIndexChanged(int index);
|
||||
void on_sampleRate_currentIndexChanged(int index);
|
||||
void on_decim_currentIndexChanged(int index);
|
||||
void on_volume_valueChanged(int value);
|
||||
void on_channels_currentIndexChanged(int index);
|
||||
void on_startStop_toggled(bool checked);
|
||||
void updateHardware();
|
||||
void openDeviceSettingsDialog(const QPoint& p);
|
||||
};
|
||||
|
||||
#endif // INCLUDE_AUDIOINPUTGUI_H
|
391
plugins/samplesource/audioinput/audioinputgui.ui
Normal file
391
plugins/samplesource/audioinput/audioinputgui.ui
Normal file
@ -0,0 +1,391 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AudioInputGui</class>
|
||||
<widget class="QWidget" name="AudioInputGui">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>320</width>
|
||||
<height>350</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>320</width>
|
||||
<height>350</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Liberation Sans</family>
|
||||
<pointsize>9</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>FunCubeDongle</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="layoutFrequency">
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="deviceUILayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="deviceButtonsLayout">
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="startStop">
|
||||
<property name="toolTip">
|
||||
<string>start/stop acquisition</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/play.png</normaloff>
|
||||
<normalon>:/stop.png</normalon>:/play.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="deviceRateLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="deviceRateText">
|
||||
<property name="toolTip">
|
||||
<string>Baseband I/Q sample rate kS/s</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>00000k</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="deviceLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="device">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>220</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="refreshDevices">
|
||||
<property name="toolTip">
|
||||
<string>Refresh list of audio devices</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/recycle.png</normaloff>:/recycle.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="sampleRateLabel">
|
||||
<property name="text">
|
||||
<string>SR</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="sampleRate">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Audio sample rate in Hz</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="sampleRateUnits">
|
||||
<property name="text">
|
||||
<string> Hz</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="decim">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Decimation factor</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>2</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>4</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>8</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="decimLabel">
|
||||
<property name="text">
|
||||
<string>Dec</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="volumeLabel">
|
||||
<property name="text">
|
||||
<string>Volume</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDial" name="volume">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Audio volume. Not supported by all devices</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="volumeText">
|
||||
<property name="text">
|
||||
<string>1.0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Channel Map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="channels">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>How audio channels map to IQ data</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>I=L, Q=0</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>I=R, Q=0</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>I=L, Q=R</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>I=R, Q=L</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="padLayout">
|
||||
<item>
|
||||
<spacer name="verticalPadSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ButtonSwitch</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>gui/buttonswitch.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../../sdrgui/resources/res.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
151
plugins/samplesource/audioinput/audioinputplugin.cpp
Normal file
151
plugins/samplesource/audioinput/audioinputplugin.cpp
Normal file
@ -0,0 +1,151 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2015 Edouard Griffiths, F4EXB //
|
||||
// Copyright (C) 2020 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/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <QtPlugin>
|
||||
#include "plugin/pluginapi.h"
|
||||
#include "util/simpleserializer.h"
|
||||
#include "audioinputplugin.h"
|
||||
#include "audioinputwebapiadapter.h"
|
||||
|
||||
#ifdef SERVER_MODE
|
||||
#include "audioinput.h"
|
||||
#else
|
||||
#include "audioinputgui.h"
|
||||
#endif
|
||||
|
||||
const PluginDescriptor AudioInputPlugin::m_pluginDescriptor = {
|
||||
QString("AudioInput"),
|
||||
QString("Audio Input"),
|
||||
QString("4.22.0"),
|
||||
QString("(c) Jon Beniston, M7RCE and Edouard Griffiths, F4EXB"),
|
||||
QString("https://github.com/f4exb/sdrangel"),
|
||||
true,
|
||||
QString("https://github.com/f4exb/sdrangel")
|
||||
};
|
||||
|
||||
const QString AudioInputPlugin::m_hardwareID = "AudioInput";
|
||||
const QString AudioInputPlugin::m_deviceTypeID = AUDIOINPUT_DEVICE_TYPE_ID;
|
||||
|
||||
AudioInputPlugin::AudioInputPlugin(QObject* parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
const PluginDescriptor& AudioInputPlugin::getPluginDescriptor() const
|
||||
{
|
||||
return m_pluginDescriptor;
|
||||
}
|
||||
|
||||
void AudioInputPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||
{
|
||||
pluginAPI->registerSampleSource(m_deviceTypeID, this);
|
||||
}
|
||||
|
||||
void AudioInputPlugin::enumOriginDevices(QStringList& listedHwIds, OriginDevices& originDevices)
|
||||
{
|
||||
if (listedHwIds.contains(m_hardwareID)) { // check if it was done
|
||||
return;
|
||||
}
|
||||
|
||||
// We could list all input audio devices here separately
|
||||
// but I thought it makes it simpler to switch between inputs
|
||||
// if they are in the AudioInput GUI
|
||||
originDevices.append(OriginDevice(
|
||||
"Audio",
|
||||
m_hardwareID,
|
||||
"0",
|
||||
0,
|
||||
1, // nb Rx
|
||||
0 // nb Tx
|
||||
));
|
||||
}
|
||||
|
||||
PluginInterface::SamplingDevices AudioInputPlugin::enumSampleSources(const OriginDevices& originDevices)
|
||||
{
|
||||
SamplingDevices result;
|
||||
|
||||
for (OriginDevices::const_iterator it = originDevices.begin(); it != originDevices.end(); ++it)
|
||||
{
|
||||
if (it->hardwareId == m_hardwareID)
|
||||
{
|
||||
for (unsigned int j = 0; j < it->nbRxStreams; j++)
|
||||
{
|
||||
result.append(SamplingDevice(
|
||||
it->displayableName,
|
||||
it->hardwareId,
|
||||
m_deviceTypeID,
|
||||
it->serial,
|
||||
it->sequence,
|
||||
PluginInterface::SamplingDevice::PhysicalDevice,
|
||||
PluginInterface::SamplingDevice::StreamSingleRx,
|
||||
it->nbRxStreams,
|
||||
j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef SERVER_MODE
|
||||
DeviceGUI* AudioInputPlugin::createSampleSourcePluginInstanceGUI(
|
||||
const QString& sourceId,
|
||||
QWidget **widget,
|
||||
DeviceUISet *deviceUISet)
|
||||
{
|
||||
(void) sourceId;
|
||||
(void) widget;
|
||||
(void) deviceUISet;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
DeviceGUI* AudioInputPlugin::createSampleSourcePluginInstanceGUI(
|
||||
const QString& sourceId,
|
||||
QWidget **widget,
|
||||
DeviceUISet *deviceUISet)
|
||||
{
|
||||
if(sourceId == m_deviceTypeID)
|
||||
{
|
||||
AudioInputGui* gui = new AudioInputGui(deviceUISet);
|
||||
*widget = gui;
|
||||
return gui;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
DeviceSampleSource *AudioInputPlugin::createSampleSourcePluginInstance(const QString& sourceId, DeviceAPI *deviceAPI)
|
||||
{
|
||||
if (sourceId == m_deviceTypeID)
|
||||
{
|
||||
AudioInputSource::AudioInput* input = new AudioInputSource::AudioInput(deviceAPI);
|
||||
return input;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
DeviceWebAPIAdapter *AudioInputPlugin::createDeviceWebAPIAdapter() const
|
||||
{
|
||||
return new AudioInputWebAPIAdapter();
|
||||
}
|
56
plugins/samplesource/audioinput/audioinputplugin.h
Normal file
56
plugins/samplesource/audioinput/audioinputplugin.h
Normal file
@ -0,0 +1,56 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2015 Edouard Griffiths, F4EXB //
|
||||
// Copyright (C) 2020 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/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_AUDIOINPUTPLUGIN_H
|
||||
#define INCLUDE_AUDIOINPUTPLUGIN_H
|
||||
|
||||
#include <QObject>
|
||||
#include "plugin/plugininterface.h"
|
||||
|
||||
#define AUDIOINPUT_DEVICE_TYPE_ID "sdrangel.samplesource.audioinput"
|
||||
|
||||
class PluginAPI;
|
||||
|
||||
class AudioInputPlugin : public QObject, public PluginInterface {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(PluginInterface)
|
||||
Q_PLUGIN_METADATA(IID AUDIOINPUT_DEVICE_TYPE_ID)
|
||||
|
||||
public:
|
||||
explicit AudioInputPlugin(QObject* parent = NULL);
|
||||
|
||||
const PluginDescriptor& getPluginDescriptor() const;
|
||||
void initPlugin(PluginAPI* pluginAPI);
|
||||
|
||||
virtual void enumOriginDevices(QStringList& listedHwIds, OriginDevices& originDevices);
|
||||
virtual SamplingDevices enumSampleSources(const OriginDevices& originDevices);
|
||||
virtual DeviceGUI* createSampleSourcePluginInstanceGUI(
|
||||
const QString& sourceId,
|
||||
QWidget **widget,
|
||||
DeviceUISet *deviceUISet);
|
||||
virtual DeviceSampleSource* createSampleSourcePluginInstance(const QString& sourceId, DeviceAPI *deviceAPI);
|
||||
virtual DeviceWebAPIAdapter* createDeviceWebAPIAdapter() const;
|
||||
|
||||
static const QString m_hardwareID;
|
||||
static const QString m_deviceTypeID;
|
||||
|
||||
private:
|
||||
static const PluginDescriptor m_pluginDescriptor;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_AUDIOINPUTPLUGIN_H
|
99
plugins/samplesource/audioinput/audioinputsettings.cpp
Normal file
99
plugins/samplesource/audioinput/audioinputsettings.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2015 Edouard Griffiths, F4EXB //
|
||||
// Copyright (C) 2020 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/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <QtGlobal>
|
||||
#include "util/simpleserializer.h"
|
||||
#include "audioinputsettings.h"
|
||||
|
||||
AudioInputSettings::AudioInputSettings()
|
||||
{
|
||||
resetToDefaults();
|
||||
}
|
||||
|
||||
void AudioInputSettings::resetToDefaults()
|
||||
{
|
||||
m_deviceName = "";
|
||||
m_sampleRate = 48000;
|
||||
m_volume = 1.0f;
|
||||
m_log2Decim = 0;
|
||||
m_iqMapping = L;
|
||||
m_useReverseAPI = false;
|
||||
m_reverseAPIAddress = "127.0.0.1";
|
||||
m_reverseAPIPort = 8888;
|
||||
m_reverseAPIDeviceIndex = 0;
|
||||
}
|
||||
|
||||
QByteArray AudioInputSettings::serialize() const
|
||||
{
|
||||
SimpleSerializer s(1);
|
||||
|
||||
s.writeString(1, m_deviceName);
|
||||
s.writeS32(2, m_sampleRate);
|
||||
s.writeFloat(3, m_volume);
|
||||
s.writeU32(4, m_log2Decim);
|
||||
s.writeS32(5, (int)m_iqMapping);
|
||||
|
||||
s.writeBool(24, m_useReverseAPI);
|
||||
s.writeString(25, m_reverseAPIAddress);
|
||||
s.writeU32(26, m_reverseAPIPort);
|
||||
s.writeU32(27, m_reverseAPIDeviceIndex);
|
||||
|
||||
return s.final();
|
||||
}
|
||||
|
||||
bool AudioInputSettings::deserialize(const QByteArray& data)
|
||||
{
|
||||
SimpleDeserializer d(data);
|
||||
|
||||
if (!d.isValid())
|
||||
{
|
||||
resetToDefaults();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (d.getVersion() == 1)
|
||||
{
|
||||
uint32_t uintval;
|
||||
|
||||
d.readString(1, &m_deviceName, "");
|
||||
d.readS32(2, &m_sampleRate, 48000);
|
||||
d.readFloat(3, &m_volume, 1.0f);
|
||||
d.readU32(4, &m_log2Decim, 0);
|
||||
d.readS32(5, (int *)&m_iqMapping, IQMapping::L);
|
||||
|
||||
d.readBool(24, &m_useReverseAPI, false);
|
||||
d.readString(25, &m_reverseAPIAddress, "127.0.0.1");
|
||||
d.readU32(26, &uintval, 0);
|
||||
|
||||
if ((uintval > 1023) && (uintval < 65535)) {
|
||||
m_reverseAPIPort = uintval;
|
||||
} else {
|
||||
m_reverseAPIPort = 8888;
|
||||
}
|
||||
|
||||
d.readU32(27, &uintval, 0);
|
||||
m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
resetToDefaults();
|
||||
return false;
|
||||
}
|
||||
}
|
64
plugins/samplesource/audioinput/audioinputsettings.h
Normal file
64
plugins/samplesource/audioinput/audioinputsettings.h
Normal file
@ -0,0 +1,64 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2015 Edouard Griffiths, F4EXB //
|
||||
// Copyright (C) 2020 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/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _AUDIOINPUT_AUDIOINPUTSETTINGS_H_
|
||||
#define _AUDIOINPUT_AUDIOINPUTSETTINGS_H_
|
||||
|
||||
#include <QString>
|
||||
#include <QAudioDeviceInfo>
|
||||
|
||||
struct AudioInputSettings {
|
||||
|
||||
QString m_deviceName; // Including realm, as from getFullDeviceName below
|
||||
int m_sampleRate;
|
||||
float m_volume;
|
||||
quint32 m_log2Decim;
|
||||
enum IQMapping {
|
||||
L,
|
||||
R,
|
||||
LR,
|
||||
RL
|
||||
} m_iqMapping;
|
||||
|
||||
bool m_useReverseAPI;
|
||||
QString m_reverseAPIAddress;
|
||||
uint16_t m_reverseAPIPort;
|
||||
uint16_t m_reverseAPIDeviceIndex;
|
||||
|
||||
AudioInputSettings();
|
||||
void resetToDefaults();
|
||||
QByteArray serialize() const;
|
||||
bool deserialize(const QByteArray& data);
|
||||
|
||||
// Append realm to device names, because there may be multiple devices with the same name on Windows
|
||||
static QString getFullDeviceName(const QAudioDeviceInfo &deviceInfo)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
return deviceInfo.deviceName();
|
||||
#else
|
||||
QString realm = deviceInfo.realm();
|
||||
if (realm != "" && realm != "default" && realm != "alsa")
|
||||
return deviceInfo.deviceName() + " " + realm;
|
||||
else
|
||||
return deviceInfo.deviceName();
|
||||
#endif
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif /* _AUDIOINPUT_AUDIOINPUTSETTINGS_H_ */
|
141
plugins/samplesource/audioinput/audioinputthread.cpp
Normal file
141
plugins/samplesource/audioinput/audioinputthread.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||
// written by Christian Daniel //
|
||||
// Copyright (C) 2020 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/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <QDebug>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "dsp/samplesinkfifo.h"
|
||||
#include "audio/audiofifo.h"
|
||||
|
||||
#include "audioinputthread.h"
|
||||
|
||||
AudioInputThread::AudioInputThread(SampleSinkFifo* sampleFifo, AudioFifo *fifo, QObject* parent) :
|
||||
QThread(parent),
|
||||
m_fifo(fifo),
|
||||
m_running(false),
|
||||
m_log2Decim(0),
|
||||
m_iqMapping(AudioInputSettings::IQMapping::L),
|
||||
m_convertBuffer(m_convBufSamples),
|
||||
m_sampleFifo(sampleFifo)
|
||||
{
|
||||
start();
|
||||
}
|
||||
|
||||
AudioInputThread::~AudioInputThread()
|
||||
{
|
||||
}
|
||||
|
||||
void AudioInputThread::startWork()
|
||||
{
|
||||
m_startWaitMutex.lock();
|
||||
|
||||
start();
|
||||
|
||||
while(!m_running)
|
||||
{
|
||||
m_startWaiter.wait(&m_startWaitMutex, 100);
|
||||
}
|
||||
|
||||
m_startWaitMutex.unlock();
|
||||
}
|
||||
|
||||
void AudioInputThread::stopWork()
|
||||
{
|
||||
m_running = false;
|
||||
wait();
|
||||
}
|
||||
|
||||
void AudioInputThread::run()
|
||||
{
|
||||
m_running = true;
|
||||
qDebug("AudioInputThread::run: start running loop");
|
||||
|
||||
while (m_running)
|
||||
{
|
||||
workIQ(m_convBufSamples);
|
||||
}
|
||||
|
||||
qDebug("AudioInputThread::run: running loop stopped");
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
void AudioInputThread::workIQ(unsigned int samples)
|
||||
{
|
||||
// Most of the time, this returns 0, because of the low sample rate.
|
||||
// Could be more efficient in this case to have blocking wait?
|
||||
uint32_t nbRead = m_fifo->read((unsigned char *) m_buf, samples);
|
||||
|
||||
// Map between left and right audio channels and IQ channels
|
||||
if (m_iqMapping == AudioInputSettings::IQMapping::L)
|
||||
{
|
||||
for (uint32_t i = 0; i < nbRead; i++)
|
||||
m_buf[i*2+1] = 0;
|
||||
}
|
||||
else if (m_iqMapping == AudioInputSettings::IQMapping::R)
|
||||
{
|
||||
for (uint32_t i = 0; i < nbRead; i++)
|
||||
{
|
||||
m_buf[i*2] = m_buf[i*2+1];
|
||||
m_buf[i*2+1] = 0;
|
||||
}
|
||||
}
|
||||
else if (m_iqMapping == AudioInputSettings::IQMapping::LR)
|
||||
{
|
||||
for (uint32_t i = 0; i < nbRead; i++)
|
||||
{
|
||||
qint16 t = m_buf[i*2];
|
||||
m_buf[i*2] = m_buf[i*2+1];
|
||||
m_buf[i*2+1] = t;
|
||||
}
|
||||
}
|
||||
|
||||
SampleVector::iterator it = m_convertBuffer.begin();
|
||||
|
||||
switch (m_log2Decim)
|
||||
{
|
||||
case 0:
|
||||
m_decimatorsIQ.decimate1(&it, m_buf, 2*nbRead);
|
||||
break;
|
||||
case 1:
|
||||
m_decimatorsIQ.decimate2_cen(&it, m_buf, 2*nbRead);
|
||||
break;
|
||||
case 2:
|
||||
m_decimatorsIQ.decimate4_cen(&it, m_buf, 2*nbRead);
|
||||
break;
|
||||
case 3:
|
||||
m_decimatorsIQ.decimate8_cen(&it, m_buf, 2*nbRead);
|
||||
break;
|
||||
case 4:
|
||||
m_decimatorsIQ.decimate16_cen(&it, m_buf, 2*nbRead);
|
||||
break;
|
||||
case 5:
|
||||
m_decimatorsIQ.decimate32_cen(&it, m_buf, 2*nbRead);
|
||||
break;
|
||||
case 6:
|
||||
m_decimatorsIQ.decimate64_cen(&it, m_buf, 2*nbRead);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_sampleFifo->write(m_convertBuffer.begin(), it);
|
||||
}
|
63
plugins/samplesource/audioinput/audioinputthread.h
Normal file
63
plugins/samplesource/audioinput/audioinputthread.h
Normal file
@ -0,0 +1,63 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2015-2018 Edouard Griffiths, F4EXB //
|
||||
// Copyright (C) 2020 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/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_AUDIOINPUTTHREAD_H
|
||||
#define INCLUDE_AUDIOINPUTTHREAD_H
|
||||
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
|
||||
#include "dsp/samplesinkfifo.h"
|
||||
#include "dsp/decimators.h"
|
||||
#include "audioinputsettings.h"
|
||||
|
||||
class AudioFifo;
|
||||
|
||||
class AudioInputThread : public QThread {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AudioInputThread(SampleSinkFifo* sampleFifo, AudioFifo *fifo, QObject* parent = nullptr);
|
||||
~AudioInputThread();
|
||||
|
||||
void startWork();
|
||||
void stopWork();
|
||||
void setLog2Decimation(unsigned int log2_decim) {m_log2Decim = log2_decim;}
|
||||
void setIQMapping(AudioInputSettings::IQMapping iqMapping) {m_iqMapping = iqMapping;}
|
||||
|
||||
static const int m_convBufSamples = 4096;
|
||||
private:
|
||||
AudioFifo* m_fifo;
|
||||
|
||||
QMutex m_startWaitMutex;
|
||||
QWaitCondition m_startWaiter;
|
||||
bool m_running;
|
||||
unsigned int m_log2Decim;
|
||||
AudioInputSettings::IQMapping m_iqMapping;
|
||||
|
||||
qint16 m_buf[m_convBufSamples*2]; // stereo (I, Q)
|
||||
SampleVector m_convertBuffer;
|
||||
SampleSinkFifo* m_sampleFifo;
|
||||
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 16, true> m_decimatorsIQ;
|
||||
|
||||
void run();
|
||||
void workIQ(unsigned int samples);
|
||||
};
|
||||
|
||||
#endif // INCLUDE_AUDIOINPUTTHREAD_H
|
49
plugins/samplesource/audioinput/audioinputwebapiadapter.cpp
Normal file
49
plugins/samplesource/audioinput/audioinputwebapiadapter.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
|
||||
// Copyright (C) 2020 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/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SWGDeviceSettings.h"
|
||||
#include "audioinput.h"
|
||||
#include "audioinputwebapiadapter.h"
|
||||
|
||||
AudioInputWebAPIAdapter::AudioInputWebAPIAdapter()
|
||||
{}
|
||||
|
||||
AudioInputWebAPIAdapter::~AudioInputWebAPIAdapter()
|
||||
{}
|
||||
|
||||
int AudioInputWebAPIAdapter::webapiSettingsGet(
|
||||
SWGSDRangel::SWGDeviceSettings& response,
|
||||
QString& errorMessage)
|
||||
{
|
||||
(void) errorMessage;
|
||||
response.setAirspyHfSettings(new SWGSDRangel::SWGAirspyHFSettings());
|
||||
response.getAirspyHfSettings()->init();
|
||||
AudioInputSource::AudioInput::webapiFormatDeviceSettings(response, m_settings);
|
||||
return 200;
|
||||
}
|
||||
|
||||
int AudioInputWebAPIAdapter::webapiSettingsPutPatch(
|
||||
bool force,
|
||||
const QStringList& deviceSettingsKeys,
|
||||
SWGSDRangel::SWGDeviceSettings& response, // query + response
|
||||
QString& errorMessage)
|
||||
{
|
||||
(void) errorMessage;
|
||||
AudioInputSource::AudioInput::webapiUpdateDeviceSettings(m_settings, deviceSettingsKeys, response);
|
||||
return 200;
|
||||
}
|
42
plugins/samplesource/audioinput/audioinputwebapiadapter.h
Normal file
42
plugins/samplesource/audioinput/audioinputwebapiadapter.h
Normal file
@ -0,0 +1,42 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
|
||||
// Copyright (C) 2020 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/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "device/devicewebapiadapter.h"
|
||||
#include "audioinputsettings.h"
|
||||
|
||||
class AudioInputWebAPIAdapter : public DeviceWebAPIAdapter
|
||||
{
|
||||
public:
|
||||
AudioInputWebAPIAdapter();
|
||||
virtual ~AudioInputWebAPIAdapter();
|
||||
virtual QByteArray serialize() { return m_settings.serialize(); }
|
||||
virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); }
|
||||
|
||||
virtual int webapiSettingsGet(
|
||||
SWGSDRangel::SWGDeviceSettings& response,
|
||||
QString& errorMessage);
|
||||
|
||||
virtual int webapiSettingsPutPatch(
|
||||
bool force,
|
||||
const QStringList& deviceSettingsKeys,
|
||||
SWGSDRangel::SWGDeviceSettings& response, // query + response
|
||||
QString& errorMessage);
|
||||
|
||||
private:
|
||||
AudioInputSettings m_settings;
|
||||
};
|
46
plugins/samplesource/audioinput/readme.md
Normal file
46
plugins/samplesource/audioinput/readme.md
Normal file
@ -0,0 +1,46 @@
|
||||
<h1>Audio input plugin</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
This input sample source plugin gets its samples from an audio device.
|
||||
|
||||
<h2>Interface</h2>
|
||||
|
||||
![Audio input plugin GUI](../../../doc/img/AudioInput_plugin.png)
|
||||
|
||||
<h3>1: Start/Stop</h3>
|
||||
|
||||
Device start / stop button.
|
||||
|
||||
- Blue triangle icon: device is ready and can be started
|
||||
- Green square icon: device is running and can be stopped
|
||||
- Magenta (or pink) square icon: an error occurred. In the case the device was accidentally disconnected you may click on the icon, plug back in and start again.
|
||||
|
||||
<h3>2: Device</h3>
|
||||
|
||||
The audio device to use.
|
||||
|
||||
<h3>3: Refresh devices</h3>
|
||||
|
||||
Refresh the list of audio devices.
|
||||
|
||||
<h3>4: Audio sample rate</h3>
|
||||
|
||||
Audio sample rate in Hz (Sa/s).
|
||||
|
||||
<h3>5: Decimation</h3>
|
||||
|
||||
A decimation factor to apply to the audio data. The baseband sample rate will be the audio sample, divided by this decimation factor.
|
||||
|
||||
<h3>6: Volume</h3>
|
||||
|
||||
A control to set the input volume. This is not supported by all input audio devices.
|
||||
|
||||
<h3>7: Channel Map</h3>
|
||||
|
||||
This controls how the left and right stereo audio channels map on to the IQ channels.
|
||||
|
||||
* I=L, Q=0 - The left audio channel is driven to the I channel. The Q channel is set to 0.
|
||||
* I=R, Q=0 - The right audio channel is driven to the I channel. The Q channel is set to 0.
|
||||
* I=L, Q=R - The left audio channel is driven to the I channel. The right audio channel is driven to the Q channel.
|
||||
* I=R, Q=L - The right audio channel is driven to the I channel. The left audio channel is driven to the Q channel.
|
@ -189,3 +189,9 @@ qint64 AudioInput::writeData(const char *data, qint64 len)
|
||||
return len;
|
||||
}
|
||||
|
||||
void AudioInput::setVolume(float volume)
|
||||
{
|
||||
m_volume = volume;
|
||||
if (m_audioInput != nullptr)
|
||||
m_audioInput->setVolume(m_volume);
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
|
||||
uint getRate() const { return m_audioFormat.sampleRate(); }
|
||||
void setOnExit(bool onExit) { m_onExit = onExit; }
|
||||
void setVolume(float volume) { m_volume = volume; }
|
||||
void setVolume(float volume);
|
||||
|
||||
private:
|
||||
QMutex m_mutex;
|
||||
|
@ -1574,6 +1574,44 @@ margin-bottom: 20px;
|
||||
}
|
||||
},
|
||||
"description" : "Audio input device"
|
||||
};
|
||||
defs.AudioInputSettings = {
|
||||
"properties" : {
|
||||
"device" : {
|
||||
"type" : "string",
|
||||
"description" : "The name of the audio device"
|
||||
},
|
||||
"devSampleRate" : {
|
||||
"type" : "integer",
|
||||
"description" : "Audio sample rate"
|
||||
},
|
||||
"volume" : {
|
||||
"type" : "number",
|
||||
"format" : "float"
|
||||
},
|
||||
"log2Decim" : {
|
||||
"type" : "integer",
|
||||
"description" : "Decimation factor"
|
||||
},
|
||||
"iqMapping" : {
|
||||
"type" : "integer",
|
||||
"description" : "Audio channel to IQ mapping\n * 0 - I=L, Q=0\n * 1 - I=R, Q=0\n * 2 - I=L, Q=R\n * 3 - I=R, Q=L\n"
|
||||
},
|
||||
"useReverseAPI" : {
|
||||
"type" : "integer",
|
||||
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
|
||||
},
|
||||
"reverseAPIAddress" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"reverseAPIPort" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"reverseAPIDeviceIndex" : {
|
||||
"type" : "integer"
|
||||
}
|
||||
},
|
||||
"description" : "AudioInput"
|
||||
};
|
||||
defs.AudioOutputDevice = {
|
||||
"properties" : {
|
||||
@ -3428,6 +3466,9 @@ margin-bottom: 20px;
|
||||
"airspyHFSettings" : {
|
||||
"$ref" : "#/definitions/AirspyHFSettings"
|
||||
},
|
||||
"audioInputSettings" : {
|
||||
"$ref" : "#/definitions/AudioInputSettings"
|
||||
},
|
||||
"bladeRF1InputSettings" : {
|
||||
"$ref" : "#/definitions/BladeRF1InputSettings"
|
||||
},
|
||||
@ -40584,7 +40625,7 @@ except ApiException as e:
|
||||
</div>
|
||||
<div id="generator">
|
||||
<div class="content">
|
||||
Generated 2020-11-09T17:45:17.371+01:00
|
||||
Generated 2020-11-09T22:06:31.158+01:00
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3800,6 +3800,11 @@ bool WebAPIRequestMapper::getDeviceSettings(
|
||||
deviceSettings->setAirspyHfSettings(new SWGSDRangel::SWGAirspyHFSettings());
|
||||
deviceSettings->getAirspyHfSettings()->fromJsonObject(settingsJsonObject);
|
||||
}
|
||||
else if (deviceSettingsKey == "audioInputSettings")
|
||||
{
|
||||
deviceSettings->setAudioInputSettings(new SWGSDRangel::SWGAudioInputSettings());
|
||||
deviceSettings->getAudioInputSettings()->fromJsonObject(settingsJsonObject);
|
||||
}
|
||||
else if (deviceSettingsKey == "bladeRF1InputSettings")
|
||||
{
|
||||
deviceSettings->setBladeRf1InputSettings(new SWGSDRangel::SWGBladeRF1InputSettings());
|
||||
@ -4109,6 +4114,7 @@ void WebAPIRequestMapper::resetDeviceSettings(SWGSDRangel::SWGDeviceSettings& de
|
||||
deviceSettings.setDeviceHwType(nullptr);
|
||||
deviceSettings.setAirspySettings(nullptr);
|
||||
deviceSettings.setAirspyHfSettings(nullptr);
|
||||
deviceSettings.setAudioInputSettings(nullptr);
|
||||
deviceSettings.setBladeRf1InputSettings(nullptr);
|
||||
deviceSettings.setBladeRf1OutputSettings(nullptr);
|
||||
deviceSettings.setFcdProPlusSettings(nullptr);
|
||||
|
@ -68,6 +68,7 @@ const QMap<QString, QString> WebAPIUtils::m_channelURIToSettingsKey = {
|
||||
const QMap<QString, QString> WebAPIUtils::m_deviceIdToSettingsKey = {
|
||||
{"sdrangel.samplesource.airspy", "airspySettings"},
|
||||
{"sdrangel.samplesource.airspyhf", "airspyHFSettings"},
|
||||
{"sdrangel.samplesource.audio", "audioInputSettings"},
|
||||
{"sdrangel.samplesource.bladerf1input", "bladeRF1InputSettings"},
|
||||
{"sdrangel.samplesource.bladerf", "bladeRF1InputSettings"}, // remap
|
||||
{"sdrangel.samplesink.bladerf1output", "bladeRF1OutputSettings"},
|
||||
@ -156,6 +157,7 @@ const QMap<QString, QString> WebAPIUtils::m_channelTypeToActionsKey = {
|
||||
const QMap<QString, QString> WebAPIUtils::m_sourceDeviceHwIdToSettingsKey = {
|
||||
{"Airspy", "airspySettings"},
|
||||
{"AirspyHF", "airspyHFSettings"},
|
||||
{"AudioInput", "audioInputSettings"},
|
||||
{"BladeRF1", "bladeRF1InputSettings"},
|
||||
{"BladeRF2", "bladeRF2InputSettings"},
|
||||
{"FCDPro", "fcdProSettings"},
|
||||
@ -180,6 +182,7 @@ const QMap<QString, QString> WebAPIUtils::m_sourceDeviceHwIdToSettingsKey = {
|
||||
const QMap<QString, QString> WebAPIUtils::m_sourceDeviceHwIdToActionsKey = {
|
||||
{"Airspy", "airspyActions"},
|
||||
{"AirspyHF", "airspyHFActions"},
|
||||
{"AudioInput", "audioInputActions"},
|
||||
{"BladeRF1", "bladeRF1InputActions"},
|
||||
{"FCDPro", "fcdProActions"},
|
||||
{"FCDPro+", "fcdProPlusActions"},
|
||||
|
32
swagger/sdrangel/api/swagger/include/AudioInput.yaml
Normal file
32
swagger/sdrangel/api/swagger/include/AudioInput.yaml
Normal file
@ -0,0 +1,32 @@
|
||||
AudioInputSettings:
|
||||
description: AudioInput
|
||||
properties:
|
||||
device:
|
||||
description: The name of the audio device
|
||||
type: string
|
||||
devSampleRate:
|
||||
description: Audio sample rate
|
||||
type: integer
|
||||
volume:
|
||||
type: number
|
||||
format: float
|
||||
log2Decim:
|
||||
description: Decimation factor
|
||||
type: integer
|
||||
iqMapping:
|
||||
type: integer
|
||||
description: >
|
||||
Audio channel to IQ mapping
|
||||
* 0 - I=L, Q=0
|
||||
* 1 - I=R, Q=0
|
||||
* 2 - I=L, Q=R
|
||||
* 3 - I=R, Q=L
|
||||
useReverseAPI:
|
||||
description: Synchronize with reverse API (1 for yes, 0 for no)
|
||||
type: integer
|
||||
reverseAPIAddress:
|
||||
type: string
|
||||
reverseAPIPort:
|
||||
type: integer
|
||||
reverseAPIDeviceIndex:
|
||||
type: integer
|
@ -18,6 +18,8 @@ DeviceSettings:
|
||||
$ref: "http://swgserver:8081/api/swagger/include/Airspy.yaml#/AirspySettings"
|
||||
airspyHFSettings:
|
||||
$ref: "http://swgserver:8081/api/swagger/include/AirspyHF.yaml#/AirspyHFSettings"
|
||||
audioInputSettings:
|
||||
$ref: "http://swgserver:8081/api/swagger/include/AudioInput.yaml#/AudioInputSettings"
|
||||
bladeRF1InputSettings:
|
||||
$ref: "http://swgserver:8081/api/swagger/include/BladeRF1.yaml#/BladeRF1InputSettings"
|
||||
bladeRF2InputSettings:
|
||||
|
@ -1574,6 +1574,44 @@ margin-bottom: 20px;
|
||||
}
|
||||
},
|
||||
"description" : "Audio input device"
|
||||
};
|
||||
defs.AudioInputSettings = {
|
||||
"properties" : {
|
||||
"device" : {
|
||||
"type" : "string",
|
||||
"description" : "The name of the audio device"
|
||||
},
|
||||
"devSampleRate" : {
|
||||
"type" : "integer",
|
||||
"description" : "Audio sample rate"
|
||||
},
|
||||
"volume" : {
|
||||
"type" : "number",
|
||||
"format" : "float"
|
||||
},
|
||||
"log2Decim" : {
|
||||
"type" : "integer",
|
||||
"description" : "Decimation factor"
|
||||
},
|
||||
"iqMapping" : {
|
||||
"type" : "integer",
|
||||
"description" : "Audio channel to IQ mapping\n * 0 - I=L, Q=0\n * 1 - I=R, Q=0\n * 2 - I=L, Q=R\n * 3 - I=R, Q=L\n"
|
||||
},
|
||||
"useReverseAPI" : {
|
||||
"type" : "integer",
|
||||
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
|
||||
},
|
||||
"reverseAPIAddress" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"reverseAPIPort" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"reverseAPIDeviceIndex" : {
|
||||
"type" : "integer"
|
||||
}
|
||||
},
|
||||
"description" : "AudioInput"
|
||||
};
|
||||
defs.AudioOutputDevice = {
|
||||
"properties" : {
|
||||
@ -3428,6 +3466,9 @@ margin-bottom: 20px;
|
||||
"airspyHFSettings" : {
|
||||
"$ref" : "#/definitions/AirspyHFSettings"
|
||||
},
|
||||
"audioInputSettings" : {
|
||||
"$ref" : "#/definitions/AudioInputSettings"
|
||||
},
|
||||
"bladeRF1InputSettings" : {
|
||||
"$ref" : "#/definitions/BladeRF1InputSettings"
|
||||
},
|
||||
@ -40584,7 +40625,7 @@ except ApiException as e:
|
||||
</div>
|
||||
<div id="generator">
|
||||
<div class="content">
|
||||
Generated 2020-11-09T17:45:17.371+01:00
|
||||
Generated 2020-11-09T22:06:31.158+01:00
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
296
swagger/sdrangel/code/qt5/client/SWGAudioInputSettings.cpp
Normal file
296
swagger/sdrangel/code/qt5/client/SWGAudioInputSettings.cpp
Normal file
@ -0,0 +1,296 @@
|
||||
/**
|
||||
* SDRangel
|
||||
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
|
||||
*
|
||||
* OpenAPI spec version: 4.15.0
|
||||
* Contact: f4exb06@gmail.com
|
||||
*
|
||||
* NOTE: This class is auto generated by the swagger code generator program.
|
||||
* https://github.com/swagger-api/swagger-codegen.git
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
#include "SWGAudioInputSettings.h"
|
||||
|
||||
#include "SWGHelpers.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QObject>
|
||||
#include <QDebug>
|
||||
|
||||
namespace SWGSDRangel {
|
||||
|
||||
SWGAudioInputSettings::SWGAudioInputSettings(QString* json) {
|
||||
init();
|
||||
this->fromJson(*json);
|
||||
}
|
||||
|
||||
SWGAudioInputSettings::SWGAudioInputSettings() {
|
||||
device = nullptr;
|
||||
m_device_isSet = false;
|
||||
dev_sample_rate = 0;
|
||||
m_dev_sample_rate_isSet = false;
|
||||
volume = 0.0f;
|
||||
m_volume_isSet = false;
|
||||
log2_decim = 0;
|
||||
m_log2_decim_isSet = false;
|
||||
iq_mapping = 0;
|
||||
m_iq_mapping_isSet = false;
|
||||
use_reverse_api = 0;
|
||||
m_use_reverse_api_isSet = false;
|
||||
reverse_api_address = nullptr;
|
||||
m_reverse_api_address_isSet = false;
|
||||
reverse_api_port = 0;
|
||||
m_reverse_api_port_isSet = false;
|
||||
reverse_api_device_index = 0;
|
||||
m_reverse_api_device_index_isSet = false;
|
||||
}
|
||||
|
||||
SWGAudioInputSettings::~SWGAudioInputSettings() {
|
||||
this->cleanup();
|
||||
}
|
||||
|
||||
void
|
||||
SWGAudioInputSettings::init() {
|
||||
device = new QString("");
|
||||
m_device_isSet = false;
|
||||
dev_sample_rate = 0;
|
||||
m_dev_sample_rate_isSet = false;
|
||||
volume = 0.0f;
|
||||
m_volume_isSet = false;
|
||||
log2_decim = 0;
|
||||
m_log2_decim_isSet = false;
|
||||
iq_mapping = 0;
|
||||
m_iq_mapping_isSet = false;
|
||||
use_reverse_api = 0;
|
||||
m_use_reverse_api_isSet = false;
|
||||
reverse_api_address = new QString("");
|
||||
m_reverse_api_address_isSet = false;
|
||||
reverse_api_port = 0;
|
||||
m_reverse_api_port_isSet = false;
|
||||
reverse_api_device_index = 0;
|
||||
m_reverse_api_device_index_isSet = false;
|
||||
}
|
||||
|
||||
void
|
||||
SWGAudioInputSettings::cleanup() {
|
||||
if(device != nullptr) {
|
||||
delete device;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if(reverse_api_address != nullptr) {
|
||||
delete reverse_api_address;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
SWGAudioInputSettings*
|
||||
SWGAudioInputSettings::fromJson(QString &json) {
|
||||
QByteArray array (json.toStdString().c_str());
|
||||
QJsonDocument doc = QJsonDocument::fromJson(array);
|
||||
QJsonObject jsonObject = doc.object();
|
||||
this->fromJsonObject(jsonObject);
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
SWGAudioInputSettings::fromJsonObject(QJsonObject &pJson) {
|
||||
::SWGSDRangel::setValue(&device, pJson["device"], "QString", "QString");
|
||||
|
||||
::SWGSDRangel::setValue(&dev_sample_rate, pJson["devSampleRate"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&volume, pJson["volume"], "float", "");
|
||||
|
||||
::SWGSDRangel::setValue(&log2_decim, pJson["log2Decim"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&iq_mapping, pJson["iqMapping"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString");
|
||||
|
||||
::SWGSDRangel::setValue(&reverse_api_port, pJson["reverseAPIPort"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&reverse_api_device_index, pJson["reverseAPIDeviceIndex"], "qint32", "");
|
||||
|
||||
}
|
||||
|
||||
QString
|
||||
SWGAudioInputSettings::asJson ()
|
||||
{
|
||||
QJsonObject* obj = this->asJsonObject();
|
||||
|
||||
QJsonDocument doc(*obj);
|
||||
QByteArray bytes = doc.toJson();
|
||||
delete obj;
|
||||
return QString(bytes);
|
||||
}
|
||||
|
||||
QJsonObject*
|
||||
SWGAudioInputSettings::asJsonObject() {
|
||||
QJsonObject* obj = new QJsonObject();
|
||||
if(device != nullptr && *device != QString("")){
|
||||
toJsonValue(QString("device"), device, obj, QString("QString"));
|
||||
}
|
||||
if(m_dev_sample_rate_isSet){
|
||||
obj->insert("devSampleRate", QJsonValue(dev_sample_rate));
|
||||
}
|
||||
if(m_volume_isSet){
|
||||
obj->insert("volume", QJsonValue(volume));
|
||||
}
|
||||
if(m_log2_decim_isSet){
|
||||
obj->insert("log2Decim", QJsonValue(log2_decim));
|
||||
}
|
||||
if(m_iq_mapping_isSet){
|
||||
obj->insert("iqMapping", QJsonValue(iq_mapping));
|
||||
}
|
||||
if(m_use_reverse_api_isSet){
|
||||
obj->insert("useReverseAPI", QJsonValue(use_reverse_api));
|
||||
}
|
||||
if(reverse_api_address != nullptr && *reverse_api_address != QString("")){
|
||||
toJsonValue(QString("reverseAPIAddress"), reverse_api_address, obj, QString("QString"));
|
||||
}
|
||||
if(m_reverse_api_port_isSet){
|
||||
obj->insert("reverseAPIPort", QJsonValue(reverse_api_port));
|
||||
}
|
||||
if(m_reverse_api_device_index_isSet){
|
||||
obj->insert("reverseAPIDeviceIndex", QJsonValue(reverse_api_device_index));
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
QString*
|
||||
SWGAudioInputSettings::getDevice() {
|
||||
return device;
|
||||
}
|
||||
void
|
||||
SWGAudioInputSettings::setDevice(QString* device) {
|
||||
this->device = device;
|
||||
this->m_device_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGAudioInputSettings::getDevSampleRate() {
|
||||
return dev_sample_rate;
|
||||
}
|
||||
void
|
||||
SWGAudioInputSettings::setDevSampleRate(qint32 dev_sample_rate) {
|
||||
this->dev_sample_rate = dev_sample_rate;
|
||||
this->m_dev_sample_rate_isSet = true;
|
||||
}
|
||||
|
||||
float
|
||||
SWGAudioInputSettings::getVolume() {
|
||||
return volume;
|
||||
}
|
||||
void
|
||||
SWGAudioInputSettings::setVolume(float volume) {
|
||||
this->volume = volume;
|
||||
this->m_volume_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGAudioInputSettings::getLog2Decim() {
|
||||
return log2_decim;
|
||||
}
|
||||
void
|
||||
SWGAudioInputSettings::setLog2Decim(qint32 log2_decim) {
|
||||
this->log2_decim = log2_decim;
|
||||
this->m_log2_decim_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGAudioInputSettings::getIqMapping() {
|
||||
return iq_mapping;
|
||||
}
|
||||
void
|
||||
SWGAudioInputSettings::setIqMapping(qint32 iq_mapping) {
|
||||
this->iq_mapping = iq_mapping;
|
||||
this->m_iq_mapping_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGAudioInputSettings::getUseReverseApi() {
|
||||
return use_reverse_api;
|
||||
}
|
||||
void
|
||||
SWGAudioInputSettings::setUseReverseApi(qint32 use_reverse_api) {
|
||||
this->use_reverse_api = use_reverse_api;
|
||||
this->m_use_reverse_api_isSet = true;
|
||||
}
|
||||
|
||||
QString*
|
||||
SWGAudioInputSettings::getReverseApiAddress() {
|
||||
return reverse_api_address;
|
||||
}
|
||||
void
|
||||
SWGAudioInputSettings::setReverseApiAddress(QString* reverse_api_address) {
|
||||
this->reverse_api_address = reverse_api_address;
|
||||
this->m_reverse_api_address_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGAudioInputSettings::getReverseApiPort() {
|
||||
return reverse_api_port;
|
||||
}
|
||||
void
|
||||
SWGAudioInputSettings::setReverseApiPort(qint32 reverse_api_port) {
|
||||
this->reverse_api_port = reverse_api_port;
|
||||
this->m_reverse_api_port_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGAudioInputSettings::getReverseApiDeviceIndex() {
|
||||
return reverse_api_device_index;
|
||||
}
|
||||
void
|
||||
SWGAudioInputSettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) {
|
||||
this->reverse_api_device_index = reverse_api_device_index;
|
||||
this->m_reverse_api_device_index_isSet = true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SWGAudioInputSettings::isSet(){
|
||||
bool isObjectUpdated = false;
|
||||
do{
|
||||
if(device && *device != QString("")){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_dev_sample_rate_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_volume_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_log2_decim_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_iq_mapping_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_use_reverse_api_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(reverse_api_address && *reverse_api_address != QString("")){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_reverse_api_port_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_reverse_api_device_index_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
}while(false);
|
||||
return isObjectUpdated;
|
||||
}
|
||||
}
|
||||
|
107
swagger/sdrangel/code/qt5/client/SWGAudioInputSettings.h
Normal file
107
swagger/sdrangel/code/qt5/client/SWGAudioInputSettings.h
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* SDRangel
|
||||
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
|
||||
*
|
||||
* OpenAPI spec version: 4.15.0
|
||||
* Contact: f4exb06@gmail.com
|
||||
*
|
||||
* NOTE: This class is auto generated by the swagger code generator program.
|
||||
* https://github.com/swagger-api/swagger-codegen.git
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SWGAudioInputSettings.h
|
||||
*
|
||||
* AudioInput
|
||||
*/
|
||||
|
||||
#ifndef SWGAudioInputSettings_H_
|
||||
#define SWGAudioInputSettings_H_
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "SWGObject.h"
|
||||
#include "export.h"
|
||||
|
||||
namespace SWGSDRangel {
|
||||
|
||||
class SWG_API SWGAudioInputSettings: public SWGObject {
|
||||
public:
|
||||
SWGAudioInputSettings();
|
||||
SWGAudioInputSettings(QString* json);
|
||||
virtual ~SWGAudioInputSettings();
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
virtual QString asJson () override;
|
||||
virtual QJsonObject* asJsonObject() override;
|
||||
virtual void fromJsonObject(QJsonObject &json) override;
|
||||
virtual SWGAudioInputSettings* fromJson(QString &jsonString) override;
|
||||
|
||||
QString* getDevice();
|
||||
void setDevice(QString* device);
|
||||
|
||||
qint32 getDevSampleRate();
|
||||
void setDevSampleRate(qint32 dev_sample_rate);
|
||||
|
||||
float getVolume();
|
||||
void setVolume(float volume);
|
||||
|
||||
qint32 getLog2Decim();
|
||||
void setLog2Decim(qint32 log2_decim);
|
||||
|
||||
qint32 getIqMapping();
|
||||
void setIqMapping(qint32 iq_mapping);
|
||||
|
||||
qint32 getUseReverseApi();
|
||||
void setUseReverseApi(qint32 use_reverse_api);
|
||||
|
||||
QString* getReverseApiAddress();
|
||||
void setReverseApiAddress(QString* reverse_api_address);
|
||||
|
||||
qint32 getReverseApiPort();
|
||||
void setReverseApiPort(qint32 reverse_api_port);
|
||||
|
||||
qint32 getReverseApiDeviceIndex();
|
||||
void setReverseApiDeviceIndex(qint32 reverse_api_device_index);
|
||||
|
||||
|
||||
virtual bool isSet() override;
|
||||
|
||||
private:
|
||||
QString* device;
|
||||
bool m_device_isSet;
|
||||
|
||||
qint32 dev_sample_rate;
|
||||
bool m_dev_sample_rate_isSet;
|
||||
|
||||
float volume;
|
||||
bool m_volume_isSet;
|
||||
|
||||
qint32 log2_decim;
|
||||
bool m_log2_decim_isSet;
|
||||
|
||||
qint32 iq_mapping;
|
||||
bool m_iq_mapping_isSet;
|
||||
|
||||
qint32 use_reverse_api;
|
||||
bool m_use_reverse_api_isSet;
|
||||
|
||||
QString* reverse_api_address;
|
||||
bool m_reverse_api_address_isSet;
|
||||
|
||||
qint32 reverse_api_port;
|
||||
bool m_reverse_api_port_isSet;
|
||||
|
||||
qint32 reverse_api_device_index;
|
||||
bool m_reverse_api_device_index_isSet;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SWGAudioInputSettings_H_ */
|
@ -38,6 +38,8 @@ SWGDeviceSettings::SWGDeviceSettings() {
|
||||
m_airspy_settings_isSet = false;
|
||||
airspy_hf_settings = nullptr;
|
||||
m_airspy_hf_settings_isSet = false;
|
||||
audio_input_settings = nullptr;
|
||||
m_audio_input_settings_isSet = false;
|
||||
blade_rf1_input_settings = nullptr;
|
||||
m_blade_rf1_input_settings_isSet = false;
|
||||
blade_rf2_input_settings = nullptr;
|
||||
@ -114,6 +116,8 @@ SWGDeviceSettings::init() {
|
||||
m_airspy_settings_isSet = false;
|
||||
airspy_hf_settings = new SWGAirspyHFSettings();
|
||||
m_airspy_hf_settings_isSet = false;
|
||||
audio_input_settings = new SWGAudioInputSettings();
|
||||
m_audio_input_settings_isSet = false;
|
||||
blade_rf1_input_settings = new SWGBladeRF1InputSettings();
|
||||
m_blade_rf1_input_settings_isSet = false;
|
||||
blade_rf2_input_settings = new SWGBladeRF2InputSettings();
|
||||
@ -187,6 +191,9 @@ SWGDeviceSettings::cleanup() {
|
||||
if(airspy_hf_settings != nullptr) {
|
||||
delete airspy_hf_settings;
|
||||
}
|
||||
if(audio_input_settings != nullptr) {
|
||||
delete audio_input_settings;
|
||||
}
|
||||
if(blade_rf1_input_settings != nullptr) {
|
||||
delete blade_rf1_input_settings;
|
||||
}
|
||||
@ -297,6 +304,8 @@ SWGDeviceSettings::fromJsonObject(QJsonObject &pJson) {
|
||||
|
||||
::SWGSDRangel::setValue(&airspy_hf_settings, pJson["airspyHFSettings"], "SWGAirspyHFSettings", "SWGAirspyHFSettings");
|
||||
|
||||
::SWGSDRangel::setValue(&audio_input_settings, pJson["audioInputSettings"], "SWGAudioInputSettings", "SWGAudioInputSettings");
|
||||
|
||||
::SWGSDRangel::setValue(&blade_rf1_input_settings, pJson["bladeRF1InputSettings"], "SWGBladeRF1InputSettings", "SWGBladeRF1InputSettings");
|
||||
|
||||
::SWGSDRangel::setValue(&blade_rf2_input_settings, pJson["bladeRF2InputSettings"], "SWGBladeRF2InputSettings", "SWGBladeRF2InputSettings");
|
||||
@ -386,6 +395,9 @@ SWGDeviceSettings::asJsonObject() {
|
||||
if((airspy_hf_settings != nullptr) && (airspy_hf_settings->isSet())){
|
||||
toJsonValue(QString("airspyHFSettings"), airspy_hf_settings, obj, QString("SWGAirspyHFSettings"));
|
||||
}
|
||||
if((audio_input_settings != nullptr) && (audio_input_settings->isSet())){
|
||||
toJsonValue(QString("audioInputSettings"), audio_input_settings, obj, QString("SWGAudioInputSettings"));
|
||||
}
|
||||
if((blade_rf1_input_settings != nullptr) && (blade_rf1_input_settings->isSet())){
|
||||
toJsonValue(QString("bladeRF1InputSettings"), blade_rf1_input_settings, obj, QString("SWGBladeRF1InputSettings"));
|
||||
}
|
||||
@ -527,6 +539,16 @@ SWGDeviceSettings::setAirspyHfSettings(SWGAirspyHFSettings* airspy_hf_settings)
|
||||
this->m_airspy_hf_settings_isSet = true;
|
||||
}
|
||||
|
||||
SWGAudioInputSettings*
|
||||
SWGDeviceSettings::getAudioInputSettings() {
|
||||
return audio_input_settings;
|
||||
}
|
||||
void
|
||||
SWGDeviceSettings::setAudioInputSettings(SWGAudioInputSettings* audio_input_settings) {
|
||||
this->audio_input_settings = audio_input_settings;
|
||||
this->m_audio_input_settings_isSet = true;
|
||||
}
|
||||
|
||||
SWGBladeRF1InputSettings*
|
||||
SWGDeviceSettings::getBladeRf1InputSettings() {
|
||||
return blade_rf1_input_settings;
|
||||
@ -837,6 +859,9 @@ SWGDeviceSettings::isSet(){
|
||||
if(airspy_hf_settings && airspy_hf_settings->isSet()){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(audio_input_settings && audio_input_settings->isSet()){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(blade_rf1_input_settings && blade_rf1_input_settings->isSet()){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "SWGAirspyHFSettings.h"
|
||||
#include "SWGAirspySettings.h"
|
||||
#include "SWGAudioInputSettings.h"
|
||||
#include "SWGBladeRF1InputSettings.h"
|
||||
#include "SWGBladeRF1OutputSettings.h"
|
||||
#include "SWGBladeRF2InputSettings.h"
|
||||
@ -88,6 +89,9 @@ public:
|
||||
SWGAirspyHFSettings* getAirspyHfSettings();
|
||||
void setAirspyHfSettings(SWGAirspyHFSettings* airspy_hf_settings);
|
||||
|
||||
SWGAudioInputSettings* getAudioInputSettings();
|
||||
void setAudioInputSettings(SWGAudioInputSettings* audio_input_settings);
|
||||
|
||||
SWGBladeRF1InputSettings* getBladeRf1InputSettings();
|
||||
void setBladeRf1InputSettings(SWGBladeRF1InputSettings* blade_rf1_input_settings);
|
||||
|
||||
@ -194,6 +198,9 @@ private:
|
||||
SWGAirspyHFSettings* airspy_hf_settings;
|
||||
bool m_airspy_hf_settings_isSet;
|
||||
|
||||
SWGAudioInputSettings* audio_input_settings;
|
||||
bool m_audio_input_settings_isSet;
|
||||
|
||||
SWGBladeRF1InputSettings* blade_rf1_input_settings;
|
||||
bool m_blade_rf1_input_settings_isSet;
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "SWGArgValue.h"
|
||||
#include "SWGAudioDevices.h"
|
||||
#include "SWGAudioInputDevice.h"
|
||||
#include "SWGAudioInputSettings.h"
|
||||
#include "SWGAudioOutputDevice.h"
|
||||
#include "SWGBFMDemodReport.h"
|
||||
#include "SWGBFMDemodSettings.h"
|
||||
@ -279,6 +280,9 @@ namespace SWGSDRangel {
|
||||
if(QString("SWGAudioInputDevice").compare(type) == 0) {
|
||||
return new SWGAudioInputDevice();
|
||||
}
|
||||
if(QString("SWGAudioInputSettings").compare(type) == 0) {
|
||||
return new SWGAudioInputSettings();
|
||||
}
|
||||
if(QString("SWGAudioOutputDevice").compare(type) == 0) {
|
||||
return new SWGAudioOutputDevice();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user