Multiple audio support: extend audio output information to UDP/RTP information. New audio preferences dialog

This commit is contained in:
f4exb 2018-03-25 11:50:34 +02:00
parent bfce9a4fcc
commit 745e187e2b
16 changed files with 391 additions and 34 deletions

View File

@ -63,7 +63,7 @@ AMDemod::AMDemod(DeviceSourceAPI *deviceAPI) :
m_magsq = 0.0;
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo, getInputMessageQueue());
m_audioNetSink = new AudioNetSink(0); // parent thread allocated dynamically
m_audioNetSink->setDestination(m_settings.m_udpAddress, m_settings.m_udpPort);

View File

@ -84,7 +84,7 @@ BFMDemod::BFMDemod(DeviceSourceAPI *deviceAPI) :
m_audioBuffer.resize(16384);
m_audioBufferFill = 0;
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo, getInputMessageQueue());
m_audioNetSink = new AudioNetSink(0); // parent thread allocated dynamically
m_audioNetSink->setDestination(m_settings.m_udpAddress, m_settings.m_udpPort);
m_audioNetSink->setStereo(true);

View File

@ -72,8 +72,8 @@ DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) :
m_magsqPeak = 0.0f;
m_magsqCount = 0;
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo1);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo2);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo1, getInputMessageQueue());
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo2, getInputMessageQueue());
// m_udpBufferAudio = new UDPSink<AudioSample>(this, m_udpBlockSize, m_settings.m_udpPort);
// m_audioFifo1.setUDPSink(m_udpBufferAudio);

View File

@ -80,7 +80,7 @@ NFMDemod::NFMDemod(DeviceSourceAPI *devieAPI) :
m_ctcssDetector.setCoefficients(3000, 6000.0); // 0.5s / 2 Hz resolution
m_afSquelch.setCoefficients(24, 600, 48000.0, 200, 0); // 0.5ms test period, 300ms average span, 48kS/s SR, 100ms attack, no decay
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo, getInputMessageQueue());
m_audioNetSink = new AudioNetSink(0); // parent thread allocated dynamically
m_audioNetSink->setDestination(m_settings.m_udpAddress, m_settings.m_udpPort);

View File

@ -85,7 +85,7 @@ SSBDemod::SSBDemod(DeviceSourceAPI *deviceAPI) :
SSBFilter = new fftfilt(m_LowCutoff / m_audioSampleRate, m_Bandwidth / m_audioSampleRate, ssbFftLen);
DSBFilter = new fftfilt((2.0f * m_Bandwidth) / m_audioSampleRate, 2 * ssbFftLen);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo, getInputMessageQueue());
m_audioNetSink = new AudioNetSink(0); // parent thread allocated dynamically
m_audioNetSink->setDestination(m_settings.m_udpAddress, m_settings.m_udpPort);

View File

@ -59,7 +59,7 @@ WFMDemod::WFMDemod(DeviceSourceAPI* deviceAPI) :
m_audioBuffer.resize(16384);
m_audioBufferFill = 0;
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo, getInputMessageQueue());
m_audioNetSink = new AudioNetSink(0); // parent thread allocated dynamically
m_audioNetSink->setDestination(m_settings.m_udpAddress, m_settings.m_udpPort);

View File

@ -543,7 +543,7 @@ void UDPSrc::applySettings(const UDPSrcSettings& settings, bool force)
if (settings.m_audioActive)
{
m_audioBufferFill = 0;
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo, getInputMessageQueue());
}
else
{

View File

@ -66,7 +66,7 @@ AMMod::AMMod(DeviceSinkAPI *deviceAPI) :
m_magsq = 0.0;
m_toneNco.setFreq(1000.0, m_settings.m_audioSampleRate);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo, getInputMessageQueue());
// CW keyer
m_cwKeyer.setSampleRate(m_settings.m_audioSampleRate);

View File

@ -73,7 +73,7 @@ NFMMod::NFMMod(DeviceSinkAPI *deviceAPI) :
m_toneNco.setFreq(1000.0, m_settings.m_audioSampleRate);
m_ctcssNco.setFreq(88.5, m_settings.m_audioSampleRate);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo, getInputMessageQueue());
// CW keyer
m_cwKeyer.setSampleRate(m_settings.m_audioSampleRate);

View File

@ -88,7 +88,7 @@ SSBMod::SSBMod(DeviceSinkAPI *deviceAPI) :
m_magsq = 0.0;
m_toneNco.setFreq(1000.0, m_settings.m_audioSampleRate);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo, getInputMessageQueue());
// CW keyer
m_cwKeyer.setSampleRate(m_settings.m_audioSampleRate);

View File

@ -75,7 +75,7 @@ WFMMod::WFMMod(DeviceSinkAPI *deviceAPI) :
m_toneNco.setFreq(1000.0, m_settings.m_audioSampleRate);
m_toneNcoRF.setFreq(1000.0, m_outputSampleRate);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo, getInputMessageQueue());
// CW keyer
m_cwKeyer.setSampleRate(m_outputSampleRate);

View File

@ -18,9 +18,11 @@
#include "audio/audiodevicemanager.h"
#include "util/simpleserializer.h"
#include <QDataStream>
#include <QDebug>
const float AudioDeviceManager::m_defaultAudioInputVolume = 0.15f;
const QString AudioDeviceManager::m_defaultUDPAddress = "127.0.0.1";
QDataStream& operator<<(QDataStream& ds, const AudioDeviceManager::InputDeviceInfo& info)
{
@ -34,6 +36,18 @@ QDataStream& operator>>(QDataStream& ds, AudioDeviceManager::InputDeviceInfo& in
return ds;
}
QDataStream& operator<<(QDataStream& ds, const AudioDeviceManager::OutputDeviceInfo& info)
{
ds << info.sampleRate << info.udpAddress << info.udpPort << info.copyToUDP << info.udpStereo << info.udpUseRTP;
return ds;
}
QDataStream& operator>>(QDataStream& ds, AudioDeviceManager::OutputDeviceInfo& info)
{
ds >> info.sampleRate >> info.udpAddress >> info.udpPort >> info.copyToUDP >> info.udpStereo >> info.udpUseRTP;
return ds;
}
AudioDeviceManager::AudioDeviceManager()
{
m_inputDevicesInfo = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
@ -122,7 +136,7 @@ void AudioDeviceManager::serializeInputMap(QByteArray& data) const
void AudioDeviceManager::serializeOutputMap(QByteArray& data) const
{
QDataStream *stream = new QDataStream(&data, QIODevice::WriteOnly);
*stream << m_audioOutputSampleRates;
*stream << m_audioOutputInfos;
delete stream;
}
@ -167,10 +181,10 @@ void AudioDeviceManager::deserializeInputMap(QByteArray& data)
void AudioDeviceManager::deserializeOutputMap(QByteArray& data)
{
QDataStream readStream(&data, QIODevice::ReadOnly);
readStream >> m_audioOutputSampleRates;
readStream >> m_audioOutputInfos;
}
void AudioDeviceManager::addAudioSink(AudioFifo* audioFifo, int outputDeviceIndex)
void AudioDeviceManager::addAudioSink(AudioFifo* audioFifo, MessageQueue *sampleSinkMessageQueue, int outputDeviceIndex)
{
qDebug("AudioDeviceManager::addAudioSink: %d: %p", outputDeviceIndex, audioFifo);
@ -198,6 +212,7 @@ void AudioDeviceManager::addAudioSink(AudioFifo* audioFifo, int outputDeviceInde
}
m_audioSinkFifos[audioFifo] = outputDeviceIndex; // register audio FIFO
m_sampleSinkMessageQueues[audioFifo] = sampleSinkMessageQueue;
}
void AudioDeviceManager::removeAudioSink(AudioFifo* audioFifo)
@ -218,9 +233,10 @@ void AudioDeviceManager::removeAudioSink(AudioFifo* audioFifo)
}
m_audioSinkFifos.remove(audioFifo); // unregister audio FIFO
m_sampleSinkMessageQueues.remove(audioFifo);
}
void AudioDeviceManager::addAudioSource(AudioFifo* audioFifo, int inputDeviceIndex)
void AudioDeviceManager::addAudioSource(AudioFifo* audioFifo, MessageQueue *sampleSourceMessageQueue, int inputDeviceIndex)
{
qDebug("AudioDeviceManager::addAudioSource: %d: %p", inputDeviceIndex, audioFifo);
@ -248,6 +264,7 @@ void AudioDeviceManager::addAudioSource(AudioFifo* audioFifo, int inputDeviceInd
}
m_audioSourceFifos[audioFifo] = inputDeviceIndex; // register audio FIFO
m_sampleSourceMessageQueues[audioFifo] = sampleSourceMessageQueue;
}
void AudioDeviceManager::removeAudioSource(AudioFifo* audioFifo)
@ -268,23 +285,47 @@ void AudioDeviceManager::removeAudioSource(AudioFifo* audioFifo)
}
m_audioSourceFifos.remove(audioFifo); // unregister audio FIFO
m_sampleSourceMessageQueues.remove(audioFifo);
}
void AudioDeviceManager::startAudioOutput(int outputDeviceIndex)
{
unsigned int sampleRate;
QString udpAddress;
quint16 udpPort;
bool copyAudioToUDP;
bool udpStereo;
bool udpUseRTP;
QString deviceName;
if (getOutputDeviceName(outputDeviceIndex, deviceName))
{
if (m_audioOutputSampleRates.find(deviceName) == m_audioOutputSampleRates.end()) {
if (m_audioOutputInfos.find(deviceName) == m_audioOutputInfos.end())
{
sampleRate = m_defaultAudioSampleRate;
} else {
sampleRate = m_audioOutputSampleRates[deviceName];
udpAddress = m_defaultUDPAddress;
udpPort = m_defaultUDPPort;
copyAudioToUDP = false;
udpStereo = false;
udpUseRTP = false;
}
else
{
sampleRate = m_audioOutputInfos[deviceName].sampleRate;
udpAddress = m_audioOutputInfos[deviceName].udpAddress;
udpPort = m_audioOutputInfos[deviceName].udpPort;
copyAudioToUDP = m_audioOutputInfos[deviceName].copyToUDP;
udpStereo = m_audioOutputInfos[deviceName].udpStereo;
udpUseRTP = m_audioOutputInfos[deviceName].udpUseRTP;
}
m_audioOutputs[outputDeviceIndex]->start(outputDeviceIndex, sampleRate);
m_audioOutputSampleRates[deviceName] = m_audioOutputs[outputDeviceIndex]->getRate(); // update with actual rate
m_audioOutputInfos[deviceName].sampleRate = m_audioOutputs[outputDeviceIndex]->getRate(); // update with actual rate
m_audioOutputInfos[deviceName].udpAddress = udpAddress;
m_audioOutputInfos[deviceName].udpPort = udpPort;
m_audioOutputInfos[deviceName].copyToUDP = copyAudioToUDP;
m_audioOutputInfos[deviceName].udpStereo = udpStereo;
m_audioOutputInfos[deviceName].udpUseRTP = udpUseRTP;
}
else
{
@ -347,12 +388,17 @@ void AudioDeviceManager::debugAudioInputInfos() const
void AudioDeviceManager::debugAudioOutputInfos() const
{
QMap<QString, unsigned int>::const_iterator it = m_audioOutputSampleRates.begin();
QMap<QString, OutputDeviceInfo>::const_iterator it = m_audioOutputInfos.begin();
for (; it != m_audioOutputSampleRates.end(); ++it)
for (; it != m_audioOutputInfos.end(); ++it)
{
qDebug() << "AudioDeviceManager::debugAudioOutputInfos:"
<< " name: " << it.key()
<< " sampleRate: " << it.value();
<< " sampleRate: " << it.value().sampleRate
<< " udpAddress: " << it.value().udpAddress
<< " udpPort: " << it.value().udpPort
<< " copyToUDP: " << it.value().copyToUDP
<< " udpStereo: " << it.value().udpStereo
<< " udpUseRTP: " << it.value().udpUseRTP;
}
}

View File

@ -22,25 +22,51 @@
#include <QList>
#include <QMap>
#include <QAudioDeviceInfo>
#include <QDataStream>
#include "audio/audioinput.h"
#include "audio/audiooutput.h"
#include "export.h"
class QDataStream;
class AudioFifo;
class MessageQueue;
class SDRBASE_API AudioDeviceManager {
public:
class InputDeviceInfo
{
public:
InputDeviceInfo() :
sampleRate(m_defaultAudioSampleRate),
volume(m_defaultAudioInputVolume)
{}
unsigned int sampleRate;
float volume;
friend QDataStream& operator<<(QDataStream& ds, const InputDeviceInfo& info);
friend QDataStream& operator>>(QDataStream& ds, InputDeviceInfo& info);
};
class OutputDeviceInfo
{
public:
OutputDeviceInfo() :
sampleRate(m_defaultAudioSampleRate),
udpAddress(m_defaultUDPAddress),
udpPort(m_defaultUDPPort),
copyToUDP(false),
udpStereo(false),
udpUseRTP(false)
{}
unsigned int sampleRate;
QString udpAddress;
quint16 udpPort;
bool copyToUDP;
bool udpStereo;
bool udpUseRTP;
friend QDataStream& operator<<(QDataStream& ds, const OutputDeviceInfo& info);
friend QDataStream& operator>>(QDataStream& ds, OutputDeviceInfo& info);
};
AudioDeviceManager();
~AudioDeviceManager();
@ -51,24 +77,28 @@ public:
bool getOutputDeviceName(int outputDeviceIndex, QString &deviceName) const;
bool getInputDeviceName(int outputDeviceIndex, QString &deviceName) const;
void addAudioSink(AudioFifo* audioFifo, int outputDeviceIndex = -1); //!< Add the audio sink
void addAudioSink(AudioFifo* audioFifo, MessageQueue *sampleSinkMessageQueue, int outputDeviceIndex = -1); //!< Add the audio sink
void removeAudioSink(AudioFifo* audioFifo); //!< Remove the audio sink
void addAudioSource(AudioFifo* audioFifo, int inputDeviceIndex = -1); //!< Add an audio source
void addAudioSource(AudioFifo* audioFifo, MessageQueue *sampleSourceMessageQueue, int inputDeviceIndex = -1); //!< Add an audio source
void removeAudioSource(AudioFifo* audioFifo); //!< Remove an audio source
static const unsigned int m_defaultAudioSampleRate = 48000;
static const float m_defaultAudioInputVolume;
private:
static const QString m_defaultUDPAddress;
static const quint16 m_defaultUDPPort = 9998;
private:
QList<QAudioDeviceInfo> m_inputDevicesInfo;
QList<QAudioDeviceInfo> m_outputDevicesInfo;
QMap<AudioFifo*, int> m_audioSinkFifos; //< Audio sink FIFO to audio output device index-1 map
QMap<AudioFifo*, int> m_audioSinkFifos; //< audio sink FIFO to audio output device index-1 map
QMap<AudioFifo*, MessageQueue*> m_sampleSinkMessageQueues; //!< audio sink FIFO to attached sink message queue
QMap<int, AudioOutput*> m_audioOutputs; //!< audio device index to audio output map (index -1 is default device)
QMap<QString, unsigned int> m_audioOutputSampleRates; //!< audio device name to audio sample rate
QMap<QString, OutputDeviceInfo> m_audioOutputInfos; //!< audio device name to audio output info
QMap<AudioFifo*, int> m_audioSourceFifos; //< Audio source FIFO to audio input device index-1 map
QMap<AudioFifo*, int> m_audioSourceFifos; //< audio source FIFO to audio input device index-1 map
QMap<AudioFifo*, MessageQueue*> m_sampleSourceMessageQueues; //!< audio source FIFO to attached source message queue
QMap<int, AudioInput*> m_audioInputs; //!< audio device index to audio input map (index -1 is default device)
QMap<QString, InputDeviceInfo> m_audioInputInfos; //!< audio device name to audio input device info
@ -94,5 +124,9 @@ private:
};
QDataStream& operator<<(QDataStream& ds, const AudioDeviceManager::InputDeviceInfo& info);
QDataStream& operator>>(QDataStream& ds, AudioDeviceManager::InputDeviceInfo& info);
QDataStream& operator<<(QDataStream& ds, const AudioDeviceManager::OutputDeviceInfo& info);
QDataStream& operator>>(QDataStream& ds, AudioDeviceManager::OutputDeviceInfo& info);
#endif // INCLUDE_AUDIODEVICEMANGER_H

View File

@ -19,12 +19,16 @@
#include <QAudioFormat>
#include <QAudioDeviceInfo>
#include <QAudioOutput>
#include "audio/audiooutput.h"
#include "audio/audiofifo.h"
#include "audiooutput.h"
#include "audiofifo.h"
#include "audionetsink.h"
AudioOutput::AudioOutput() :
m_mutex(QMutex::Recursive),
m_audioOutput(0),
m_audioNetSink(0),
m_copyAudioToUdp(false),
m_udpStereo(false),
m_audioUsageCount(0),
m_onExit(false),
m_audioFifos()
@ -100,6 +104,7 @@ bool AudioOutput::start(int device, int rate)
}
m_audioOutput = new QAudioOutput(devInfo, m_audioFormat);
m_audioNetSink = new AudioNetSink(0);
QIODevice::open(QIODevice::ReadOnly);
@ -123,6 +128,8 @@ void AudioOutput::stop()
QMutexLocker mutexLocker(&m_mutex);
m_audioOutput->stop();
QIODevice::close();
delete m_audioNetSink;
m_audioNetSink = 0;
delete m_audioOutput;
// if (m_audioUsageCount > 0)
@ -162,6 +169,35 @@ bool AudioOutput::open(OpenMode mode)
return false;
}*/
void AudioOutput::setUdpDestination(const QString& address, uint16_t port)
{
if (m_audioNetSink) {
m_audioNetSink->setDestination(address, port);
}
}
void AudioOutput::setUdpCopyToUDP(bool copyToUDP)
{
m_copyAudioToUdp = copyToUDP;
}
void AudioOutput::setUdpStereo(bool stereo)
{
if (m_audioNetSink) {
m_audioNetSink->setStereo(stereo);
}
m_udpStereo = stereo;
}
void AudioOutput::setUdpUseRTP(bool useRTP)
{
if (m_audioNetSink) {
m_audioNetSink->selectType(useRTP ? AudioNetSink::SinkRTP : AudioNetSink::SinkUDP);
}
}
qint64 AudioOutput::readData(char* data, qint64 maxLen)
{
//qDebug("AudioOutput::readData: %lld", maxLen);

View File

@ -23,11 +23,13 @@
#include <QAudioFormat>
#include <list>
#include <vector>
#include <stdint.h>
#include "export.h"
class QAudioOutput;
class AudioFifo;
class AudioOutputPipe;
class AudioNetSink;
class SDRBASE_API AudioOutput : QIODevice {
public:
@ -44,9 +46,17 @@ public:
unsigned int getRate() const { return m_audioFormat.sampleRate(); }
void setOnExit(bool onExit) { m_onExit = onExit; }
void setUdpDestination(const QString& address, uint16_t port);
void setUdpCopyToUDP(bool copyToUDP);
void setUdpStereo(bool stereo);
void setUdpUseRTP(bool useRTP);
private:
QMutex m_mutex;
QAudioOutput* m_audioOutput;
AudioNetSink* m_audioNetSink;
bool m_copyAudioToUdp;
bool m_udpStereo;
uint m_audioUsageCount;
bool m_onExit;

View File

@ -23,9 +23,9 @@
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="tab_2">
<widget class="QWidget" name="tabOutput">
<attribute name="title">
<string>Audio Output</string>
</attribute>
@ -39,6 +39,176 @@
</column>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="sampleRateLayout">
<item>
<widget class="QLabel" name="outputSampleRateLabel">
<property name="text">
<string>Rate</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="outputSampleRate">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Audio output sample rate</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="minimum">
<number>8000</number>
</property>
<property name="maximum">
<number>192000</number>
</property>
<property name="singleStep">
<number>50</number>
</property>
<property name="value">
<number>48000</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<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="QPushButton" name="outputReset">
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Reset values to defaults</string>
</property>
<property name="text">
<string>R</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="udpLayout">
<item>
<widget class="QLabel" name="udpAddressLabel">
<property name="text">
<string>Addr</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="udpAddress">
<property name="maximumSize">
<size>
<width>140</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>UDP address</string>
</property>
<property name="inputMask">
<string>000.000.000.000; </string>
</property>
<property name="text">
<string>127.0.0.1</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="udpPortLabel">
<property name="text">
<string>Port</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="udpPort">
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>UDP port</string>
</property>
<property name="inputMask">
<string>00000; </string>
</property>
<property name="text">
<string>9998</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</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="ButtonSwitch" name="udpCopy">
<property name="toolTip">
<string>Copy audio to UDP</string>
</property>
<property name="text">
<string>U</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="udpStereo">
<property name="toolTip">
<string>Copy to UDP as stereo (no L+R mix)</string>
</property>
<property name="text">
<string>S</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="udpUseRTP">
<property name="toolTip">
<string>Use RTP protocol</string>
</property>
<property name="text">
<string>R</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabInput">
@ -57,6 +227,41 @@
</item>
<item>
<layout class="QHBoxLayout" name="inputVolumeLayout">
<item>
<widget class="QLabel" name="inputSampleRateLabel">
<property name="text">
<string>Rate</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="inputSampleRate">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Audio input sample rate</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="minimum">
<number>8000</number>
</property>
<property name="maximum">
<number>192000</number>
</property>
<property name="singleStep">
<number>50</number>
</property>
<property name="value">
<number>48000</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="inputVolumeLabel">
<property name="maximumSize">
@ -78,6 +283,9 @@
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Input volume</string>
</property>
<property name="maximum">
<number>100</number>
</property>
@ -118,6 +326,22 @@
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="inputReset">
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Reset values to default</string>
</property>
<property name="text">
<string>R</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
@ -136,6 +360,13 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>buttonBox</tabstop>
<tabstop>tabWidget</tabstop>