Audio output plugin

pull/717/head
f4exb 2020-11-21 11:15:06 +01:00
rodzic b3476e4757
commit 87d8816881
33 zmienionych plików z 2490 dodań i 11 usunięć

Plik binarny nie jest wyświetlany.

Po

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

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -3,6 +3,7 @@ project(samplesink)
add_subdirectory(testsink)
add_subdirectory(fileoutput)
add_subdirectory(localoutput)
add_subdirectory(audiooutput)
if(CM256CC_FOUND)
add_subdirectory(remoteoutput)

Wyświetl plik

@ -0,0 +1,57 @@
project(audiooutput)
set(audiooutput_SOURCES
audiooutput.cpp
audiooutputplugin.cpp
audiooutputsettings.cpp
# audiooutputwebapiadapter.cpp
audiooutputworker.cpp
)
set(audiooutput_HEADERS
audiooutput.h
audiooutputplugin.h
audiooutputsettings.h
# audiooutputwebapiadapter.h
audiooutputworker.h
)
include_directories(
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
)
if(NOT SERVER_MODE)
set(audiooutput_SOURCES
${audiooutput_SOURCES}
audiooutputgui.cpp
audiooutputgui.ui
)
set(audiooutput_HEADERS
${audiooutput_HEADERS}
audiooutputgui.h
)
set(TARGET_NAME outputaudio)
set(TARGET_LIB "Qt5::Widgets")
set(TARGET_LIB_GUI "sdrgui")
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
else()
set(TARGET_NAME outputaudiosrv)
set(TARGET_LIB "")
set(TARGET_LIB_GUI "")
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
endif()
add_library(${TARGET_NAME} SHARED
${audiooutput_SOURCES}
)
target_link_libraries(${TARGET_NAME}
Qt5::Core
${TARGET_LIB}
sdrbase
${TARGET_LIB_GUI}
swagger
)
install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})

Wyświetl plik

@ -0,0 +1,444 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (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 <QNetworkReply>
#include <QBuffer>
#include "SWGDeviceSettings.h"
#include "SWGDeviceState.h"
#include "device/deviceapi.h"
#include "audio/audiodevicemanager.h"
#include "dsp/dspcommands.h"
#include "dsp/dspengine.h"
#include "audiooutputworker.h"
#include "audiooutput.h"
MESSAGE_CLASS_DEFINITION(AudioOutput::MsgConfigureAudioOutput, Message)
MESSAGE_CLASS_DEFINITION(AudioOutput::MsgStartStop, Message)
AudioOutput::AudioOutput(DeviceAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
m_audioFifo(48000),
m_settings(),
m_audioDeviceIndex(-1),
m_centerFrequency(0),
m_worker(nullptr),
m_deviceDescription("AudioOutput")
{
m_deviceAPI->setNbSinkStreams(1);
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
m_sampleRate = audioDeviceManager->getOutputSampleRate(m_audioDeviceIndex);
m_settings.m_deviceName = AudioDeviceManager::m_defaultDeviceName;
m_sampleSourceFifo.resize(SampleSourceFifo::getSizePolicy(48000));
}
AudioOutput::~AudioOutput()
{
stop();
}
void AudioOutput::destroy()
{
delete this;
}
void AudioOutput::init()
{
applySettings(m_settings, true);
}
bool AudioOutput::start()
{
QMutexLocker mutexLocker(&m_mutex);
qDebug("AudioOutput::start");
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
audioDeviceManager->addAudioSink(&m_audioFifo, getInputMessageQueue(), m_audioDeviceIndex);
m_worker = new AudioOutputWorker(&m_sampleSourceFifo, &m_audioFifo);
m_worker->moveToThread(&m_workerThread);
m_worker->setSamplerate(m_sampleRate);
m_worker->setIQMapping(m_settings.m_iqMapping);
m_worker->connectTimer(m_deviceAPI->getMasterTimer());
m_worker->startWork();
m_workerThread.start();
mutexLocker.unlock();
qDebug("AudioOutput::start: started");
return true;
}
void AudioOutput::stop()
{
qDebug("AudioOutput::stop");
if (m_worker)
{
m_worker->stopWork();
m_workerThread.quit();
m_workerThread.wait();
delete m_worker;
m_worker = nullptr;
}
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
audioDeviceManager->removeAudioSink(&m_audioFifo);
m_running = false;
qDebug("AudioOutput::stop: stopped");
}
QByteArray AudioOutput::serialize() const
{
return m_settings.serialize();
}
bool AudioOutput::deserialize(const QByteArray& data)
{
bool success = true;
if (!m_settings.deserialize(data))
{
m_settings.resetToDefaults();
success = false;
}
MsgConfigureAudioOutput* message = MsgConfigureAudioOutput::create(m_settings, true);
m_inputMessageQueue.push(message);
if (m_guiMessageQueue)
{
MsgConfigureAudioOutput* messageToGUI = MsgConfigureAudioOutput::create(m_settings, true);
m_guiMessageQueue->push(messageToGUI);
}
return success;
}
const QString& AudioOutput::getDeviceDescription() const
{
return m_deviceDescription;
}
int AudioOutput::getSampleRate() const
{
return m_sampleRate;
}
quint64 AudioOutput::getCenterFrequency() const
{
return m_centerFrequency;
}
bool AudioOutput::handleMessage(const Message& message)
{
if(MsgConfigureAudioOutput::match(message))
{
qDebug() << "AudioOutput::handleMessage: MsgConfigureAudioOutput";
MsgConfigureAudioOutput& conf = (MsgConfigureAudioOutput&) message;
applySettings(conf.getSettings(), conf.getForce());
return true;
}
else if (MsgStartStop::match(message))
{
MsgStartStop& cmd = (MsgStartStop&) message;
qDebug() << "AudioOutput::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 AudioOutput::applySettings(const AudioOutputSettings& settings, bool force)
{
bool forwardChange = false;
QList<QString> reverseAPIKeys;
if ((m_settings.m_deviceName != settings.m_deviceName) || force)
{
reverseAPIKeys.append("deviceName");
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
m_audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_deviceName);
//qDebug("AMDemod::applySettings: audioDeviceName: %s audioDeviceIndex: %d", qPrintable(settings.m_audioDeviceName), audioDeviceIndex);
audioDeviceManager->removeAudioSink(&m_audioFifo);
audioDeviceManager->addAudioSink(&m_audioFifo, getInputMessageQueue(), m_audioDeviceIndex);
m_sampleRate = audioDeviceManager->getOutputSampleRate(m_audioDeviceIndex);
forwardChange = true;
}
if ((m_settings.m_volume != settings.m_volume) || force)
{
reverseAPIKeys.append("volume");
m_audioOutputDevice.setVolume(settings.m_volume);
qDebug() << "AudioOutput::applySettings: set volume to " << settings.m_volume;
}
if ((m_settings.m_iqMapping != settings.m_iqMapping) || force)
{
reverseAPIKeys.append("iqMapping");
forwardChange = true;
if (m_worker) {
m_worker->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)
{
if (m_worker) {
m_worker->setSamplerate(m_sampleRate);
}
DSPSignalNotification *notif = new DSPSignalNotification(m_sampleRate, 0);
m_centerFrequency = 0;
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
}
}
int AudioOutput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
int AudioOutput::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 AudioOutput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setAudioOutputSettings(new SWGSDRangel::SWGAudioOutputSettings());
response.getAudioOutputSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
return 200;
}
int AudioOutput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage)
{
(void) errorMessage;
AudioOutputSettings settings = m_settings;
webapiUpdateDeviceSettings(settings, deviceSettingsKeys, response);
MsgConfigureAudioOutput *msg = MsgConfigureAudioOutput::create(settings, force);
m_inputMessageQueue.push(msg);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureAudioOutput *msgToGUI = MsgConfigureAudioOutput::create(settings, force);
m_guiMessageQueue->push(msgToGUI);
}
webapiFormatDeviceSettings(response, settings);
return 200;
}
void AudioOutput::webapiUpdateDeviceSettings(
AudioOutputSettings& settings,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response)
{
if (deviceSettingsKeys.contains("deviceName")) {
settings.m_deviceName = *response.getAudioOutputSettings()->getDeviceName();
}
if (deviceSettingsKeys.contains("volume")) {
settings.m_volume = response.getAudioOutputSettings()->getVolume();
}
if (deviceSettingsKeys.contains("iqMapping")) {
settings.m_iqMapping = (AudioOutputSettings::IQMapping) response.getAudioOutputSettings()->getIqMapping();
}
if (deviceSettingsKeys.contains("useReverseAPI")) {
settings.m_useReverseAPI = response.getAudioOutputSettings()->getUseReverseApi() != 0;
}
if (deviceSettingsKeys.contains("reverseAPIAddress")) {
settings.m_reverseAPIAddress = *response.getAudioOutputSettings()->getReverseApiAddress();
}
if (deviceSettingsKeys.contains("reverseAPIPort")) {
settings.m_reverseAPIPort = response.getAudioOutputSettings()->getReverseApiPort();
}
if (deviceSettingsKeys.contains("reverseAPIDeviceIndex")) {
settings.m_reverseAPIDeviceIndex = response.getAudioOutputSettings()->getReverseApiDeviceIndex();
}
}
void AudioOutput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const AudioOutputSettings& settings)
{
response.getAudioOutputSettings()->setDeviceName(new QString(settings.m_deviceName));
response.getAudioOutputSettings()->setVolume(settings.m_volume);
response.getAudioOutputSettings()->setIqMapping((int) settings.m_iqMapping);
response.getAudioOutputSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
if (response.getAudioOutputSettings()->getReverseApiAddress()) {
*response.getAudioOutputSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
} else {
response.getAudioOutputSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
}
response.getAudioOutputSettings()->setReverseApiPort(settings.m_reverseAPIPort);
response.getAudioOutputSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
}
void AudioOutput::webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const AudioOutputSettings& settings, bool force)
{
SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings();
swgDeviceSettings->setDirection(1); // single Tx
swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
swgDeviceSettings->setDeviceHwType(new QString("AudioOutput"));
swgDeviceSettings->setAudioOutputSettings(new SWGSDRangel::SWGAudioOutputSettings());
SWGSDRangel::SWGAudioOutputSettings *swgAudioOutputSettings = swgDeviceSettings->getAudioOutputSettings();
// transfer data that has been modified. When force is on transfer all data except reverse API data
if (deviceSettingsKeys.contains("deviceName") || force) {
swgAudioOutputSettings->setDeviceName(new QString(settings.m_deviceName));
}
if (deviceSettingsKeys.contains("volume") || force) {
swgAudioOutputSettings->setVolume(settings.m_volume);
}
if (deviceSettingsKeys.contains("iqMapping") || force) {
swgAudioOutputSettings->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 AudioOutput::webapiReverseSendStartStop(bool start)
{
SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings();
swgDeviceSettings->setDirection(1); // single Tx
swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
swgDeviceSettings->setDeviceHwType(new QString("AudioOutput"));
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 AudioOutput::networkManagerFinished(QNetworkReply *reply)
{
QNetworkReply::NetworkError replyError = reply->error();
if (replyError)
{
qWarning() << "AudioOutput::networkManagerFinished:"
<< " error(" << (int) replyError
<< "): " << replyError
<< ": " << reply->errorString();
}
else
{
QString answer = reply->readAll();
answer.chop(1); // remove last \n
qDebug("AudioOutput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
}
reply->deleteLater();
}

Wyświetl plik

@ -0,0 +1,153 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (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 _AUDIOOUTPUT_AUDIOOUTPUT_H_
#define _AUDIOOUTPUT_AUDIOOUTPUT_H_
#include <QThread>
#include <QNetworkRequest>
#include "dsp/devicesamplesink.h"
#include "audio/audiooutputdevice.h"
#include "audio/audiofifo.h"
#include "audiooutputsettings.h"
class QNetworkAccessManager;
class QNetworkReply;
class AudioOutputWorker;
class DeviceAPI;
class AudioOutput : public DeviceSampleSink {
public:
class MsgConfigureAudioOutput : public Message {
MESSAGE_CLASS_DECLARATION
public:
const AudioOutputSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureAudioOutput* create(const AudioOutputSettings& settings, bool force)
{
return new MsgConfigureAudioOutput(settings, force);
}
private:
AudioOutputSettings m_settings;
bool m_force;
MsgConfigureAudioOutput(const AudioOutputSettings& 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)
{ }
};
AudioOutput(DeviceAPI *deviceAPI);
virtual ~AudioOutput();
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) { (void) centerFrequency; }
const QString& getDeviceName() const { return m_settings.m_deviceName; }
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 AudioOutputSettings& settings);
static void webapiUpdateDeviceSettings(
AudioOutputSettings& settings,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response);
private:
DeviceAPI *m_deviceAPI;
AudioOutputDevice m_audioOutputDevice;
AudioFifo m_audioFifo;
QMutex m_mutex;
AudioOutputSettings m_settings;
int m_audioDeviceIndex;
int m_sampleRate;
qint64 m_centerFrequency;
AudioOutputWorker* m_worker;
QThread m_workerThread;
QString m_deviceDescription;
bool m_running;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
void applySettings(const AudioOutputSettings& settings, bool force);
void webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const AudioOutputSettings& settings, bool force);
void webapiReverseSendStartStop(bool start);
private slots:
void networkManagerFinished(QNetworkReply *reply);
};
#endif

Wyświetl plik

@ -0,0 +1,239 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (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_audiooutputgui.h"
#include "gui/colormapper.h"
#include "gui/glspectrum.h"
#include "gui/crightclickenabler.h"
#include "gui/basicdevicesettingsdialog.h"
#include "gui/audioselectdialog.h"
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "audiooutputgui.h"
#include "device/deviceapi.h"
#include "device/deviceuiset.h"
AudioOutputGui::AudioOutputGui(DeviceUISet *deviceUISet, QWidget* parent) :
DeviceGUI(parent),
ui(new Ui::AudioOutputGui),
m_deviceUISet(deviceUISet),
m_doApplySettings(true),
m_forceSettings(true),
m_settings(),
m_centerFrequency(0)
{
m_audioOutput = (AudioOutput*) m_deviceUISet->m_deviceAPI->getSampleSink();
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 &)));
m_sampleRate = m_audioOutput->getSampleRate();
m_centerFrequency = m_audioOutput->getCenterFrequency();
m_settings.m_deviceName = m_audioOutput->getDeviceName();
updateSampleRateAndFrequency();
displaySettings();
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
m_audioOutput->setMessageQueueToGUI(&m_inputMessageQueue);
}
AudioOutputGui::~AudioOutputGui()
{
delete ui;
}
void AudioOutputGui::destroy()
{
delete this;
}
void AudioOutputGui::resetToDefaults()
{
m_settings.resetToDefaults();
displaySettings();
sendSettings();
}
QByteArray AudioOutputGui::serialize() const
{
return m_settings.serialize();
}
bool AudioOutputGui::deserialize(const QByteArray& data)
{
if(m_settings.deserialize(data))
{
displaySettings();
m_forceSettings = true;
sendSettings();
return true;
}
else
{
resetToDefaults();
return false;
}
}
bool AudioOutputGui::handleMessage(const Message& message)
{
if (AudioOutput::MsgConfigureAudioOutput::match(message))
{
const AudioOutput::MsgConfigureAudioOutput& cfg = (AudioOutput::MsgConfigureAudioOutput&) message;
m_settings = cfg.getSettings();
blockApplySettings(true);
displaySettings();
blockApplySettings(false);
return true;
}
else if (AudioOutput::MsgStartStop::match(message))
{
AudioOutput::MsgStartStop& notif = (AudioOutput::MsgStartStop&) message;
blockApplySettings(true);
ui->startStop->setChecked(notif.getStartStop());
blockApplySettings(false);
return true;
}
else
{
return false;
}
}
void AudioOutputGui::handleInputMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()) != 0)
{
qDebug("AudioOutputGui::handleInputMessages: message: %s", message->getIdentifier());
if (DSPSignalNotification::match(*message))
{
DSPSignalNotification* notif = (DSPSignalNotification*) message;
m_sampleRate = notif->getSampleRate();
m_centerFrequency = notif->getCenterFrequency();
qDebug("AudioOutputGui::handleInputMessages: DSPSignalNotification: SampleRate: %d", notif->getSampleRate());
updateSampleRateAndFrequency();
delete message;
}
else
{
if (handleMessage(*message)) {
delete message;
}
}
}
}
void AudioOutputGui::updateSampleRateAndFrequency()
{
m_deviceUISet->getSpectrum()->setSampleRate(m_sampleRate);
m_deviceUISet->getSpectrum()->setCenterFrequency(m_centerFrequency);
m_deviceUISet->getSpectrum()->setSsbSpectrum(false);
m_deviceUISet->getSpectrum()->setLsbDisplay(false);
ui->deviceRateText->setText(tr("%1k").arg((float)m_sampleRate / 1000));
}
void AudioOutputGui::displaySettings()
{
ui->deviceLabel->setText(m_settings.m_deviceName);
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);
}
void AudioOutputGui::on_deviceSelect_clicked()
{
AudioSelectDialog audioSelect(DSPEngine::instance()->getAudioDeviceManager(), m_settings.m_deviceName, false, this);
audioSelect.exec();
if (audioSelect.m_selected)
{
m_settings.m_deviceName = audioSelect.m_audioDeviceName;
ui->deviceLabel->setText(m_settings.m_deviceName);
sendSettings();
}
}
void AudioOutputGui::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 AudioOutputGui::on_channels_currentIndexChanged(int index)
{
m_settings.m_iqMapping = (AudioOutputSettings::IQMapping) index;
updateSampleRateAndFrequency();
sendSettings();
}
void AudioOutputGui::on_startStop_toggled(bool checked)
{
if (m_doApplySettings)
{
AudioOutput::MsgStartStop *message = AudioOutput::MsgStartStop::create(checked);
m_audioOutput->getInputMessageQueue()->push(message);
}
}
void AudioOutputGui::sendSettings()
{
if(!m_updateTimer.isActive())
m_updateTimer.start(100);
}
void AudioOutputGui::updateHardware()
{
if (m_doApplySettings)
{
AudioOutput::MsgConfigureAudioOutput* message = AudioOutput::MsgConfigureAudioOutput::create(m_settings, m_forceSettings);
m_audioOutput->getInputMessageQueue()->push(message);
m_forceSettings = false;
m_updateTimer.stop();
}
}
void AudioOutputGui::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();
}

Wyświetl plik

@ -0,0 +1,79 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (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_AUDIOOUTPUTGUI_H
#define INCLUDE_AUDIOOUTPUTGUI_H
#include <QTimer>
#include <QWidget>
#include "device/devicegui.h"
#include "util/messagequeue.h"
#include "audiooutput.h"
class QWidget;
class DeviceUISet;
namespace Ui {
class AudioOutputGui;
}
class AudioOutputGui : public DeviceGUI {
Q_OBJECT
public:
explicit AudioOutputGui(DeviceUISet *deviceUISet, QWidget* parent = nullptr);
virtual ~AudioOutputGui();
virtual void destroy();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
private:
Ui::AudioOutputGui* ui;
DeviceUISet* m_deviceUISet;
AudioOutput* m_audioOutput;
bool m_doApplySettings;
bool m_forceSettings;
AudioOutputSettings m_settings;
QTimer m_updateTimer;
int m_sampleRate;
qint64 m_centerFrequency;
MessageQueue m_inputMessageQueue;
void blockApplySettings(bool block) { m_doApplySettings = !block; }
void displaySettings();
void sendSettings();
void updateSampleRateAndFrequency();
bool handleMessage(const Message& message);
private slots:
void handleInputMessages();
void on_deviceSelect_clicked();
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

Wyświetl plik

@ -0,0 +1,290 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AudioOutputGui</class>
<widget class="QWidget" name="AudioOutputGui">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>320</width>
<height>200</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>200</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="windowTitle">
<string>Audio Output</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="QPushButton" name="deviceSelect">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Open dialog to select output device</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/sound_on.png</normaloff>:/sound_on.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="deviceLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Output device selected</string>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</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="channelsLabel">
<property name="text">
<string>Channels</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=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>

Wyświetl plik

@ -0,0 +1,148 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (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 "audiooutputplugin.h"
#include "audiooutputwebapiadapter.h"
#ifdef SERVER_MODE
#include "audiooutput.h"
#else
#include "audiooutputgui.h"
#endif
const PluginDescriptor AudioOutputPlugin::m_pluginDescriptor = {
QString("AudioOutput"),
QString("Audio output"),
QString("6.1.0"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
QString("https://github.com/f4exb/sdrangel")
};
const QString AudioOutputPlugin::m_hardwareID = "AudioOutput";
const QString AudioOutputPlugin::m_deviceTypeID = AUDIOOUTPUT_DEVICE_TYPE_ID;
AudioOutputPlugin::AudioOutputPlugin(QObject* parent) :
QObject(parent)
{
}
const PluginDescriptor& AudioOutputPlugin::getPluginDescriptor() const
{
return m_pluginDescriptor;
}
void AudioOutputPlugin::initPlugin(PluginAPI* pluginAPI)
{
pluginAPI->registerSampleSink(m_deviceTypeID, this);
}
void AudioOutputPlugin::enumOriginDevices(QStringList& listedHwIds, OriginDevices& originDevices)
{
if (listedHwIds.contains(m_hardwareID)) { // check if it was done
return;
}
originDevices.append(OriginDevice(
"AudioOutput",
m_hardwareID,
QString(),
0, // Sequence
0, // nb Rx
1 // nb Tx
));
listedHwIds.append(m_hardwareID);
}
PluginInterface::SamplingDevices AudioOutputPlugin::enumSampleSinks(const OriginDevices& originDevices)
{
SamplingDevices result;
for (OriginDevices::const_iterator it = originDevices.begin(); it != originDevices.end(); ++it)
{
if (it->hardwareId == m_hardwareID)
{
result.append(SamplingDevice(
it->displayableName,
it->hardwareId,
m_deviceTypeID,
it->serial,
it->sequence,
PluginInterface::SamplingDevice::BuiltInDevice,
PluginInterface::SamplingDevice::StreamSingleTx,
1,
0
));
}
}
return result;
}
#ifdef SERVER_MODE
DeviceGUI* AudioOutputPlugin::createSampleSinkPluginInstanceGUI(
const QString& sinkId,
QWidget **widget,
DeviceUISet *deviceUISet)
{
(void) sinkId;
(void) widget;
(void) deviceUISet;
return nullptr;
}
#else
DeviceGUI* AudioOutputPlugin::createSampleSinkPluginInstanceGUI(
const QString& sinkId,
QWidget **widget,
DeviceUISet *deviceUISet)
{
if (sinkId == m_deviceTypeID)
{
AudioOutputGui* gui = new AudioOutputGui(deviceUISet);
*widget = gui;
return gui;
}
else
{
return nullptr;
}
}
#endif
DeviceSampleSink* AudioOutputPlugin::createSampleSinkPluginInstance(const QString& sinkId, DeviceAPI *deviceAPI)
{
if(sinkId == m_deviceTypeID)
{
AudioOutput* output = new AudioOutput(deviceAPI);
return output;
}
else
{
return nullptr;
}
}
DeviceWebAPIAdapter *AudioOutputPlugin::createDeviceWebAPIAdapter() const
{
return new AudioOutputWebAPIAdapter();
}

Wyświetl plik

@ -0,0 +1,56 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (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_AUDIOOUTPUTPLUGIN_H
#define INCLUDE_AUDIOOUTPUTPLUGIN_H
#include <QObject>
#include "plugin/plugininterface.h"
#define AUDIOOUTPUT_DEVICE_TYPE_ID "sdrangel.samplesink.audiooutput"
class PluginAPI;
class DeviceAPI;
class AudioOutputPlugin : public QObject, public PluginInterface {
Q_OBJECT
Q_INTERFACES(PluginInterface)
Q_PLUGIN_METADATA(IID AUDIOOUTPUT_DEVICE_TYPE_ID)
public:
explicit AudioOutputPlugin(QObject* parent = nullptr);
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
virtual void enumOriginDevices(QStringList& listedHwIds, OriginDevices& originDevices);
virtual SamplingDevices enumSampleSinks(const OriginDevices& originDevices);
virtual DeviceGUI* createSampleSinkPluginInstanceGUI(
const QString& sinkId,
QWidget **widget,
DeviceUISet *deviceUISet);
virtual DeviceSampleSink* createSampleSinkPluginInstance(const QString& sinkId, DeviceAPI *deviceAPI);
virtual DeviceWebAPIAdapter* createDeviceWebAPIAdapter() const;
static const QString m_hardwareID;
static const QString m_deviceTypeID;
private:
static const PluginDescriptor m_pluginDescriptor;
};
#endif // INCLUDE_AUDIOOUTPUTPLUGIN_H

Wyświetl plik

@ -0,0 +1,93 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (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 "audiooutputsettings.h"
AudioOutputSettings::AudioOutputSettings()
{
resetToDefaults();
}
void AudioOutputSettings::resetToDefaults()
{
m_deviceName = "";
m_volume = 1.0f;
m_iqMapping = LR;
m_useReverseAPI = false;
m_reverseAPIAddress = "127.0.0.1";
m_reverseAPIPort = 8888;
m_reverseAPIDeviceIndex = 0;
}
QByteArray AudioOutputSettings::serialize() const
{
SimpleSerializer s(1);
s.writeString(1, m_deviceName);
s.writeFloat(3, m_volume);
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 AudioOutputSettings::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.readFloat(3, &m_volume, 1.0f);
d.readS32(5, (int *)&m_iqMapping, IQMapping::LR);
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;
}
}

Wyświetl plik

@ -0,0 +1,58 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (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 _AUDIOOUTPUT_AUDIOOUTPUTSETTINGS_H_
#define _AUDIOOUTPUT_AUDIOOUTPUTSETTINGS_H_
#include <QString>
#include <QAudioDeviceInfo>
struct AudioOutputSettings {
QString m_deviceName; // Including realm, as from getFullDeviceName below
float m_volume;
enum IQMapping {
LR,
RL
} m_iqMapping;
bool m_useReverseAPI;
QString m_reverseAPIAddress;
uint16_t m_reverseAPIPort;
uint16_t m_reverseAPIDeviceIndex;
AudioOutputSettings();
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 /* _AUDIOOUTPUT_AUDIOOUTPUTSETTINGS_H_ */

Wyświetl plik

@ -0,0 +1,49 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (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 "audiooutput.h"
#include "audiooutputwebapiadapter.h"
AudioOutputWebAPIAdapter::AudioOutputWebAPIAdapter()
{}
AudioOutputWebAPIAdapter::~AudioOutputWebAPIAdapter()
{}
int AudioOutputWebAPIAdapter::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setAirspyHfSettings(new SWGSDRangel::SWGAirspyHFSettings());
response.getAirspyHfSettings()->init();
AudioOutput::webapiFormatDeviceSettings(response, m_settings);
return 200;
}
int AudioOutputWebAPIAdapter::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage)
{
(void) force; // no action
(void) errorMessage;
AudioOutput::webapiUpdateDeviceSettings(m_settings, deviceSettingsKeys, response);
return 200;
}

Wyświetl plik

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (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 "audiooutputsettings.h"
class AudioOutputWebAPIAdapter : public DeviceWebAPIAdapter
{
public:
AudioOutputWebAPIAdapter();
virtual ~AudioOutputWebAPIAdapter();
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:
AudioOutputSettings m_settings;
};

Wyświetl plik

@ -0,0 +1,157 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (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 <QTimer>
#include <QDebug>
#include "dsp/samplesourcefifo.h"
#include "audio/audiofifo.h"
#include "audiooutputworker.h"
#define AUDIOOUTPUT_THROTTLE_MS 50
AudioOutputWorker::AudioOutputWorker(SampleSourceFifo* sampleFifo, AudioFifo *fifo, QObject* parent) :
QObject(parent),
m_running(false),
m_samplerate(0),
m_throttlems(AUDIOOUTPUT_THROTTLE_MS),
m_maxThrottlems(50),
m_throttleToggle(false),
m_iqMapping(AudioOutputSettings::IQMapping::LR),
m_buf(nullptr),
m_samplesChunkSize(0),
m_sampleFifo(sampleFifo),
m_audioFifo(fifo)
{
m_audioBuffer.resize(1<<14);
m_audioBufferFill = 0;
}
AudioOutputWorker::~AudioOutputWorker()
{
}
void AudioOutputWorker::startWork()
{
qDebug("AudioOutputWorker::startWork");
m_running = true;
}
void AudioOutputWorker::stopWork()
{
qDebug("AudioOutputWorker::stopWork");
m_running = false;
}
void AudioOutputWorker::connectTimer(const QTimer& timer)
{
qDebug() << "AudioOutputWorker::connectTimer";
connect(&timer, SIGNAL(timeout()), this, SLOT(tick()));
}
void AudioOutputWorker::setSamplerate(int samplerate)
{
if (samplerate != m_samplerate)
{
bool wasRunning = false;
if (m_running)
{
stopWork();
wasRunning = true;
}
// resize sample FIFO
if (m_sampleFifo) {
m_sampleFifo->resize(SampleSourceFifo::getSizePolicy(samplerate)); // 1s buffer
}
qDebug() << "AudioOutputWorker::setSamplerate:"
<< " new:" << samplerate
<< " old:" << m_samplerate
<< " m_sampleFifo size:" << m_sampleFifo->size()
<< " m_audioFifo size:" << m_audioFifo->size()
<< " sample i/q size" << sizeof(FixReal);
// resize output buffer
if (m_buf) {
delete[] m_buf;
}
m_buf = new int16_t[samplerate*2];
m_samplerate = samplerate;
m_samplesChunkSize = (m_samplerate * m_throttlems) / 1000;
if (wasRunning) {
startWork();
}
}
}
void AudioOutputWorker::tick()
{
if (m_running)
{
qint64 throttlems = m_elapsedTimer.restart();
if (throttlems != m_throttlems)
{
m_throttlems = throttlems;
m_samplesChunkSize = (m_samplerate * (m_throttlems+(m_throttleToggle ? 1 : 0))) / 1000;
m_throttleToggle = !m_throttleToggle;
}
unsigned int iPart1Begin, iPart1End, iPart2Begin, iPart2End;
SampleVector& data = m_sampleFifo->getData();
m_sampleFifo->read(m_samplesChunkSize, iPart1Begin, iPart1End, iPart2Begin, iPart2End);
if (iPart1Begin != iPart1End) {
callbackPart(data, iPart1Begin, iPart1End);
}
if (iPart2Begin != iPart2End) {
callbackPart(data, iPart2Begin, iPart2End);
}
// qDebug("AudioOutputWorker::tick: %d samples fill: %u", m_samplesChunkSize, m_audioFifo->fill());
}
}
void AudioOutputWorker::callbackPart(SampleVector& data, unsigned int iBegin, unsigned int iEnd)
{
for (unsigned int i = iBegin; i < iEnd; i++)
{
m_audioBuffer[m_audioBufferFill].l = m_iqMapping == AudioOutputSettings::LR ? data[i].m_real : data[i].m_imag;
m_audioBuffer[m_audioBufferFill].r = m_iqMapping == AudioOutputSettings::LR ? data[i].m_imag : data[i].m_real;
m_audioBufferFill++;
if (m_audioBufferFill >= m_audioBuffer.size())
{
uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill);
if (res != m_audioBufferFill)
{
qDebug("AudioOutputWorker::callbackPart: %u/%u audio samples written", res, m_audioBufferFill);
m_audioFifo->clear();
}
m_audioBufferFill = 0;
}
}
}

Wyświetl plik

@ -0,0 +1,66 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (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_AUDIOOUTPUTWORKER_H
#define INCLUDE_AUDIOOUTPUTWORKER_H
#include <QObject>
#include <QElapsedTimer>
#include "dsp/interpolators.h"
#include "audiooutputsettings.h"
class QTimer;
class SampleSourceFifo;
class AudioFifo;
class AudioOutputWorker : public QObject {
Q_OBJECT
public:
AudioOutputWorker(SampleSourceFifo* sampleFifo, AudioFifo *fifo, QObject* parent = nullptr);
~AudioOutputWorker();
void startWork();
void stopWork();
void setSamplerate(int samplerate);
void setIQMapping(AudioOutputSettings::IQMapping iqMapping) {m_iqMapping = iqMapping;}
void connectTimer(const QTimer& timer);
private:
bool m_running;
int m_samplerate;
int m_throttlems;
int m_maxThrottlems;
QElapsedTimer m_elapsedTimer;
bool m_throttleToggle;
AudioOutputSettings::IQMapping m_iqMapping;
AudioVector m_audioBuffer;
uint32_t m_audioBufferFill;
qint16 *m_buf; // stereo (I, Q)
unsigned int m_samplesChunkSize;
SampleSourceFifo* m_sampleFifo;
AudioFifo* m_audioFifo;
Interpolators<qint16, SDR_TX_SAMP_SZ, 16> m_interpolators;
void callbackPart(SampleVector& data, unsigned int iBegin, unsigned int iEnd);
private slots:
void tick();
};
#endif // INCLUDE_AUDIOOUTPUTWORKER_H

Wyświetl plik

@ -0,0 +1,36 @@
<h1>Audio output plugin</h1>
<h2>Introduction</h2>
This output plugin sends its samples to an audio device.
<h2>Interface</h2>
![Audio output plugin GUI](../../../doc/img/AudioOutput_plugin.png)
<h3>1: Start/Stop</h3>
Device start / stop button. Use this switch button to play or stop audio playback
<h3>2: Audio sample rate</h3>
Audio sample rate in Hz (Sa/s) with multiplier indicator (k).
<h3>3: Select audio device</h3>
Use this push button to open a dialog that lets you choose the audio playback device. See [audio management documentation](../../../sdrgui/audio.md) for details.
<h3>4: Audio device</h3>
The name of the audio device in use.
<h3>5: Volume</h3>
A control to set the output volume. This is not supported by all output audio devices.
<h3>6: Channel Map</h3>
This controls how the left and right audio channels map on to the IQ channels.
* I=L, Q=R - The left audio channel is driven to the I channel. The right audio channel is driven to the Q channel for a complex (analytic signal)input.
* I=R, Q=L - The right audio channel is driven to the I channel. The left audio channel is driven to the Q channel for a complex (analytic signal)input.

Wyświetl plik

@ -25,7 +25,7 @@
#define MIN(x, y) ((x) < (y) ? (x) : (y))
AudioFifo::AudioFifo() :
m_fifo(0),
m_fifo(nullptr),
m_sampleSize(sizeof(AudioSample))
{
m_size = 0;
@ -35,7 +35,7 @@ AudioFifo::AudioFifo() :
}
AudioFifo::AudioFifo(uint32_t numSamples) :
m_fifo(0),
m_fifo(nullptr),
m_sampleSize(sizeof(AudioSample))
{
QMutexLocker mutexLocker(&m_mutex);
@ -47,10 +47,10 @@ AudioFifo::~AudioFifo()
{
QMutexLocker mutexLocker(&m_mutex);
if (m_fifo != 0)
if (m_fifo)
{
delete[] m_fifo;
m_fifo = 0;
m_fifo = nullptr;
}
m_size = 0;
@ -69,7 +69,7 @@ uint AudioFifo::write(const quint8* data, uint32_t numSamples)
uint32_t remaining;
uint32_t copyLen;
if (m_fifo == 0) {
if (!m_fifo) {
return 0;
}
@ -83,6 +83,11 @@ uint AudioFifo::write(const quint8* data, uint32_t numSamples)
if (isFull())
{
m_mutex.unlock();
if (total - remaining > 0) {
emit dataReady();
}
return total - remaining; // written so far
}
@ -107,7 +112,7 @@ uint AudioFifo::read(quint8* data, uint32_t numSamples)
uint32_t remaining;
uint32_t copyLen;
if (m_fifo == 0) {
if (!m_fifo) {
return 0;
}
@ -165,10 +170,10 @@ void AudioFifo::clear()
bool AudioFifo::create(uint32_t numSamples)
{
if(m_fifo != 0)
if (m_fifo)
{
delete[] m_fifo;
m_fifo = 0;
m_fifo = nullptr;
}
m_fill = 0;

Wyświetl plik

@ -11,6 +11,7 @@
<file>webapi/doc/swagger/include/ATVDemod.yaml</file>
<file>webapi/doc/swagger/include/ATVMod.yaml</file>
<file>webapi/doc/swagger/include/AudioInput.yaml</file>
<file>webapi/doc/swagger/include/AudioOutput.yaml</file>
<file>webapi/doc/swagger/include/BeamSteeringCWMod.yaml</file>
<file>webapi/doc/swagger/include/BFMDemod.yaml</file>
<file>webapi/doc/swagger/include/BladeRF1.yaml</file>

Wyświetl plik

@ -1665,6 +1665,36 @@ margin-bottom: 20px;
}
},
"description" : "Audio output device"
};
defs.AudioOutputSettings = {
"properties" : {
"deviceName" : {
"type" : "string",
"description" : "The name of the audio device"
},
"volume" : {
"type" : "number",
"format" : "float"
},
"iqMapping" : {
"type" : "integer",
"description" : "Audio channel to IQ mapping\n * 0 - I=L, Q=R\n * 1 - 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" : "AudioOutput"
};
defs.BFMDemodReport = {
"properties" : {
@ -3600,6 +3630,9 @@ margin-bottom: 20px;
"audioInputSettings" : {
"$ref" : "#/definitions/AudioInputSettings"
},
"audioOutputSettings" : {
"$ref" : "#/definitions/AudioOutputSettings"
},
"bladeRF1InputSettings" : {
"$ref" : "#/definitions/BladeRF1InputSettings"
},
@ -44596,7 +44629,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2020-11-11T13:32:52.276+01:00
Generated 2020-11-21T10:29:19.215+01:00
</div>
</div>
</div>

Wyświetl plik

@ -0,0 +1,24 @@
AudioOutputSettings:
description: AudioOutput
properties:
deviceName:
description: The name of the audio device
type: string
volume:
type: number
format: float
iqMapping:
type: integer
description: >
Audio channel to IQ mapping
* 0 - I=L, Q=R
* 1 - 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

Wyświetl plik

@ -20,6 +20,8 @@ DeviceSettings:
$ref: "/doc/swagger/include/AirspyHF.yaml#/AirspyHFSettings"
audioInputSettings:
$ref: "/doc/swagger/include/AudioInput.yaml#/AudioInputSettings"
audioOutputSettings:
$ref: "/doc/swagger/include/AudioOutput.yaml#/AudioOutputSettings"
bladeRF1InputSettings:
$ref: "/doc/swagger/include/BladeRF1.yaml#/BladeRF1InputSettings"
bladeRF2InputSettings:

Wyświetl plik

@ -4096,6 +4096,11 @@ bool WebAPIRequestMapper::getDeviceSettings(
deviceSettings->setAudioInputSettings(new SWGSDRangel::SWGAudioInputSettings());
deviceSettings->getAudioInputSettings()->fromJsonObject(settingsJsonObject);
}
else if (deviceSettingsKey == "audioOutputSettings")
{
deviceSettings->setAudioOutputSettings(new SWGSDRangel::SWGAudioOutputSettings());
deviceSettings->getAudioOutputSettings()->fromJsonObject(settingsJsonObject);
}
else if (deviceSettingsKey == "bladeRF1InputSettings")
{
deviceSettings->setBladeRf1InputSettings(new SWGSDRangel::SWGBladeRF1InputSettings());

Wyświetl plik

@ -68,7 +68,8 @@ 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.audioinput", "audioInputSettings"},
{"sdrangel.samplesink.audiooutput", "audioOutputSettings"},
{"sdrangel.samplesource.bladerf1input", "bladeRF1InputSettings"},
{"sdrangel.samplesource.bladerf", "bladeRF1InputSettings"}, // remap
{"sdrangel.samplesink.bladerf1output", "bladeRF1OutputSettings"},
@ -204,6 +205,7 @@ const QMap<QString, QString> WebAPIUtils::m_sourceDeviceHwIdToActionsKey = {
};
const QMap<QString, QString> WebAPIUtils::m_sinkDeviceHwIdToSettingsKey = {
{"AudioOutput", "AudioOutputSettings"},
{"BladeRF1", "bladeRF1OutputSettings"},
{"BladeRF2", "bladeRF2OutputSettings"},
{"HackRF", "hackRFOutputSettings"},

Wyświetl plik

@ -0,0 +1,24 @@
AudioOutputSettings:
description: AudioOutput
properties:
deviceName:
description: The name of the audio device
type: string
volume:
type: number
format: float
iqMapping:
type: integer
description: >
Audio channel to IQ mapping
* 0 - I=L, Q=R
* 1 - 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

Wyświetl plik

@ -20,6 +20,8 @@ DeviceSettings:
$ref: "http://swgserver:8081/api/swagger/include/AirspyHF.yaml#/AirspyHFSettings"
audioInputSettings:
$ref: "http://swgserver:8081/api/swagger/include/AudioInput.yaml#/AudioInputSettings"
audioOutputSettings:
$ref: "http://swgserver:8081/api/swagger/include/AudioOutput.yaml#/AudioOutputSettings"
bladeRF1InputSettings:
$ref: "http://swgserver:8081/api/swagger/include/BladeRF1.yaml#/BladeRF1InputSettings"
bladeRF2InputSettings:

Wyświetl plik

@ -1665,6 +1665,36 @@ margin-bottom: 20px;
}
},
"description" : "Audio output device"
};
defs.AudioOutputSettings = {
"properties" : {
"deviceName" : {
"type" : "string",
"description" : "The name of the audio device"
},
"volume" : {
"type" : "number",
"format" : "float"
},
"iqMapping" : {
"type" : "integer",
"description" : "Audio channel to IQ mapping\n * 0 - I=L, Q=R\n * 1 - 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" : "AudioOutput"
};
defs.BFMDemodReport = {
"properties" : {
@ -3600,6 +3630,9 @@ margin-bottom: 20px;
"audioInputSettings" : {
"$ref" : "#/definitions/AudioInputSettings"
},
"audioOutputSettings" : {
"$ref" : "#/definitions/AudioOutputSettings"
},
"bladeRF1InputSettings" : {
"$ref" : "#/definitions/BladeRF1InputSettings"
},
@ -44596,7 +44629,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2020-11-11T13:32:52.276+01:00
Generated 2020-11-21T10:29:19.215+01:00
</div>
</div>
</div>

Wyświetl plik

@ -0,0 +1,250 @@
/**
* 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 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: 6.0.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 "SWGAudioOutputSettings.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGAudioOutputSettings::SWGAudioOutputSettings(QString* json) {
init();
this->fromJson(*json);
}
SWGAudioOutputSettings::SWGAudioOutputSettings() {
device_name = nullptr;
m_device_name_isSet = false;
volume = 0.0f;
m_volume_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;
}
SWGAudioOutputSettings::~SWGAudioOutputSettings() {
this->cleanup();
}
void
SWGAudioOutputSettings::init() {
device_name = new QString("");
m_device_name_isSet = false;
volume = 0.0f;
m_volume_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
SWGAudioOutputSettings::cleanup() {
if(device_name != nullptr) {
delete device_name;
}
if(reverse_api_address != nullptr) {
delete reverse_api_address;
}
}
SWGAudioOutputSettings*
SWGAudioOutputSettings::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGAudioOutputSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&device_name, pJson["deviceName"], "QString", "QString");
::SWGSDRangel::setValue(&volume, pJson["volume"], "float", "");
::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
SWGAudioOutputSettings::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGAudioOutputSettings::asJsonObject() {
QJsonObject* obj = new QJsonObject();
if(device_name != nullptr && *device_name != QString("")){
toJsonValue(QString("deviceName"), device_name, obj, QString("QString"));
}
if(m_volume_isSet){
obj->insert("volume", QJsonValue(volume));
}
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*
SWGAudioOutputSettings::getDeviceName() {
return device_name;
}
void
SWGAudioOutputSettings::setDeviceName(QString* device_name) {
this->device_name = device_name;
this->m_device_name_isSet = true;
}
float
SWGAudioOutputSettings::getVolume() {
return volume;
}
void
SWGAudioOutputSettings::setVolume(float volume) {
this->volume = volume;
this->m_volume_isSet = true;
}
qint32
SWGAudioOutputSettings::getIqMapping() {
return iq_mapping;
}
void
SWGAudioOutputSettings::setIqMapping(qint32 iq_mapping) {
this->iq_mapping = iq_mapping;
this->m_iq_mapping_isSet = true;
}
qint32
SWGAudioOutputSettings::getUseReverseApi() {
return use_reverse_api;
}
void
SWGAudioOutputSettings::setUseReverseApi(qint32 use_reverse_api) {
this->use_reverse_api = use_reverse_api;
this->m_use_reverse_api_isSet = true;
}
QString*
SWGAudioOutputSettings::getReverseApiAddress() {
return reverse_api_address;
}
void
SWGAudioOutputSettings::setReverseApiAddress(QString* reverse_api_address) {
this->reverse_api_address = reverse_api_address;
this->m_reverse_api_address_isSet = true;
}
qint32
SWGAudioOutputSettings::getReverseApiPort() {
return reverse_api_port;
}
void
SWGAudioOutputSettings::setReverseApiPort(qint32 reverse_api_port) {
this->reverse_api_port = reverse_api_port;
this->m_reverse_api_port_isSet = true;
}
qint32
SWGAudioOutputSettings::getReverseApiDeviceIndex() {
return reverse_api_device_index;
}
void
SWGAudioOutputSettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) {
this->reverse_api_device_index = reverse_api_device_index;
this->m_reverse_api_device_index_isSet = true;
}
bool
SWGAudioOutputSettings::isSet(){
bool isObjectUpdated = false;
do{
if(device_name && *device_name != QString("")){
isObjectUpdated = true; break;
}
if(m_volume_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;
}
}

Wyświetl plik

@ -0,0 +1,95 @@
/**
* 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 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: 6.0.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.
*/
/*
* SWGAudioOutputSettings.h
*
* AudioOutput
*/
#ifndef SWGAudioOutputSettings_H_
#define SWGAudioOutputSettings_H_
#include <QJsonObject>
#include <QString>
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGAudioOutputSettings: public SWGObject {
public:
SWGAudioOutputSettings();
SWGAudioOutputSettings(QString* json);
virtual ~SWGAudioOutputSettings();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGAudioOutputSettings* fromJson(QString &jsonString) override;
QString* getDeviceName();
void setDeviceName(QString* device_name);
float getVolume();
void setVolume(float volume);
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_name;
bool m_device_name_isSet;
float volume;
bool m_volume_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 /* SWGAudioOutputSettings_H_ */

Wyświetl plik

@ -40,6 +40,8 @@ SWGDeviceSettings::SWGDeviceSettings() {
m_airspy_hf_settings_isSet = false;
audio_input_settings = nullptr;
m_audio_input_settings_isSet = false;
audio_output_settings = nullptr;
m_audio_output_settings_isSet = false;
blade_rf1_input_settings = nullptr;
m_blade_rf1_input_settings_isSet = false;
blade_rf2_input_settings = nullptr;
@ -130,6 +132,8 @@ SWGDeviceSettings::init() {
m_airspy_hf_settings_isSet = false;
audio_input_settings = new SWGAudioInputSettings();
m_audio_input_settings_isSet = false;
audio_output_settings = new SWGAudioOutputSettings();
m_audio_output_settings_isSet = false;
blade_rf1_input_settings = new SWGBladeRF1InputSettings();
m_blade_rf1_input_settings_isSet = false;
blade_rf2_input_settings = new SWGBladeRF2InputSettings();
@ -218,6 +222,9 @@ SWGDeviceSettings::cleanup() {
if(audio_input_settings != nullptr) {
delete audio_input_settings;
}
if(audio_output_settings != nullptr) {
delete audio_output_settings;
}
if(blade_rf1_input_settings != nullptr) {
delete blade_rf1_input_settings;
}
@ -348,6 +355,8 @@ SWGDeviceSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&audio_input_settings, pJson["audioInputSettings"], "SWGAudioInputSettings", "SWGAudioInputSettings");
::SWGSDRangel::setValue(&audio_output_settings, pJson["audioOutputSettings"], "SWGAudioOutputSettings", "SWGAudioOutputSettings");
::SWGSDRangel::setValue(&blade_rf1_input_settings, pJson["bladeRF1InputSettings"], "SWGBladeRF1InputSettings", "SWGBladeRF1InputSettings");
::SWGSDRangel::setValue(&blade_rf2_input_settings, pJson["bladeRF2InputSettings"], "SWGBladeRF2InputSettings", "SWGBladeRF2InputSettings");
@ -452,6 +461,9 @@ SWGDeviceSettings::asJsonObject() {
if((audio_input_settings != nullptr) && (audio_input_settings->isSet())){
toJsonValue(QString("audioInputSettings"), audio_input_settings, obj, QString("SWGAudioInputSettings"));
}
if((audio_output_settings != nullptr) && (audio_output_settings->isSet())){
toJsonValue(QString("audioOutputSettings"), audio_output_settings, obj, QString("SWGAudioOutputSettings"));
}
if((blade_rf1_input_settings != nullptr) && (blade_rf1_input_settings->isSet())){
toJsonValue(QString("bladeRF1InputSettings"), blade_rf1_input_settings, obj, QString("SWGBladeRF1InputSettings"));
}
@ -621,6 +633,16 @@ SWGDeviceSettings::setAudioInputSettings(SWGAudioInputSettings* audio_input_sett
this->m_audio_input_settings_isSet = true;
}
SWGAudioOutputSettings*
SWGDeviceSettings::getAudioOutputSettings() {
return audio_output_settings;
}
void
SWGDeviceSettings::setAudioOutputSettings(SWGAudioOutputSettings* audio_output_settings) {
this->audio_output_settings = audio_output_settings;
this->m_audio_output_settings_isSet = true;
}
SWGBladeRF1InputSettings*
SWGDeviceSettings::getBladeRf1InputSettings() {
return blade_rf1_input_settings;
@ -994,6 +1016,9 @@ SWGDeviceSettings::isSet(){
if(audio_input_settings && audio_input_settings->isSet()){
isObjectUpdated = true; break;
}
if(audio_output_settings && audio_output_settings->isSet()){
isObjectUpdated = true; break;
}
if(blade_rf1_input_settings && blade_rf1_input_settings->isSet()){
isObjectUpdated = true; break;
}

Wyświetl plik

@ -25,6 +25,7 @@
#include "SWGAirspyHFSettings.h"
#include "SWGAirspySettings.h"
#include "SWGAudioInputSettings.h"
#include "SWGAudioOutputSettings.h"
#include "SWGBladeRF1InputSettings.h"
#include "SWGBladeRF1OutputSettings.h"
#include "SWGBladeRF2InputSettings.h"
@ -98,6 +99,9 @@ public:
SWGAudioInputSettings* getAudioInputSettings();
void setAudioInputSettings(SWGAudioInputSettings* audio_input_settings);
SWGAudioOutputSettings* getAudioOutputSettings();
void setAudioOutputSettings(SWGAudioOutputSettings* audio_output_settings);
SWGBladeRF1InputSettings* getBladeRf1InputSettings();
void setBladeRf1InputSettings(SWGBladeRF1InputSettings* blade_rf1_input_settings);
@ -225,6 +229,9 @@ private:
SWGAudioInputSettings* audio_input_settings;
bool m_audio_input_settings_isSet;
SWGAudioOutputSettings* audio_output_settings;
bool m_audio_output_settings_isSet;
SWGBladeRF1InputSettings* blade_rf1_input_settings;
bool m_blade_rf1_input_settings_isSet;

Wyświetl plik

@ -38,6 +38,7 @@
#include "SWGAudioInputDevice.h"
#include "SWGAudioInputSettings.h"
#include "SWGAudioOutputDevice.h"
#include "SWGAudioOutputSettings.h"
#include "SWGBFMDemodReport.h"
#include "SWGBFMDemodSettings.h"
#include "SWGBandwidth.h"
@ -306,6 +307,9 @@ namespace SWGSDRangel {
if(QString("SWGAudioOutputDevice").compare(type) == 0) {
return new SWGAudioOutputDevice();
}
if(QString("SWGAudioOutputSettings").compare(type) == 0) {
return new SWGAudioOutputSettings();
}
if(QString("SWGBFMDemodReport").compare(type) == 0) {
return new SWGBFMDemodReport();
}