Add QtMultimedia as default audio

merge-requests/5/head
Phil Taylor 2021-06-04 08:24:26 +01:00
rodzic 9de6d64dab
commit 24ce16b0b9
11 zmienionych plików z 482 dodań i 215 usunięć

Wyświetl plik

@ -7,25 +7,16 @@
#include "logcategories.h"
#include "ulaw.h"
audioHandler::audioHandler(QObject* parent) :
isInitialized(false),
isUlaw(false),
audioLatency(0),
isInput(0),
chunkAvailable(false)
audioHandler::audioHandler(QObject* parent)
{
Q_UNUSED(parent)
}
audioHandler::~audioHandler()
{
//stop();
if (resampler != Q_NULLPTR) {
speex_resampler_destroy(resampler);
}
if (isInitialized) {
#if defined(RTAUDIO)
try {
audio->abortStream();
@ -34,34 +25,74 @@ audioHandler::~audioHandler()
catch (RtAudioError& e) {
qInfo(logAudio()) << "Error closing stream:" << aParams.deviceId << ":" << QString::fromStdString(e.getMessage());
}
}
if (audio != Q_NULLPTR) {
delete audio;
#elif defined(PORTAUDIO)
#else
stop();
if (audioOutput != Q_NULLPTR) {
//audioOutput->stop();
delete audioOutput;
qDebug(logAudio()) << "Audio output stopped";
}
if (audioInput != Q_NULLPTR) {
//audioInput->stop();
delete audioInput;
qDebug(logAudio()) << "Audio input stopped";
}
#endif
}
if (ringBuf != Q_NULLPTR) {
delete ringBuf;
}
if (resampler != Q_NULLPTR) {
speex_resampler_destroy(resampler);
qDebug(logAudio()) << "Resampler closed";
}
}
bool audioHandler::init(const quint8 bits, const quint8 radioChan, const quint16 samplerate, const quint16 latency, const bool ulaw, const bool isinput, int port, quint8 resampleQuality)
bool audioHandler::init(audioSetup setupIn)
{
if (isInitialized) {
return false;
}
this->audioLatency = latency;
this->isUlaw = ulaw;
this->isInput = isinput;
this->radioSampleBits = bits;
this->radioSampleRate = samplerate;
this->radioChannels = radioChan;
/*
0x01 uLaw 1ch 8bit
0x02 PCM 1ch 8bit
0x04 PCM 1ch 16bit
0x08 PCM 2ch 8bit
0x10 PCM 2ch 16bit
0x20 uLaw 2ch 8bit
*/
// chunk size is always relative to Internal Sample Rate.
setup = setupIn;
setup.radioChan = 1;
setup.bits = 8;
if (setup.codec == 0x01 || setup.codec == 0x20) {
setup.ulaw = true;
}
if (setup.codec == 0x08 || setup.codec == 0x10 || setup.codec == 0x20) {
setup.radioChan = 2;
}
if (setup.codec == 0x04 || setup.codec == 0x10) {
setup.bits = 16;
}
ringBuf = new wilt::Ring<audioPacket>(100); // Should be customizable.
tempBuf.sent = 0;
#if defined(RTAUDIO)
#if !defined(Q_OS_MACX)
options.flags = ((!RTAUDIO_HOG_DEVICE) | (RTAUDIO_MINIMIZE_LATENCY));
#endif
#if defined(Q_OS_LINUX)
audio = new RtAudio(RtAudio::Api::LINUX_ALSA);
#elif defined(Q_OS_WIN)
@ -70,12 +101,10 @@ bool audioHandler::init(const quint8 bits, const quint8 radioChan, const quint16
audio = new RtAudio(RtAudio::Api::MACOSX_CORE);
#endif
tempBuf.sent = 0;
if (port > 0) {
aParams.deviceId = port;
}
else if (isInput) {
else if (setup.isinput) {
aParams.deviceId = audio->getDefaultInputDevice();
}
else {
@ -105,7 +134,7 @@ bool audioHandler::init(const quint8 bits, const quint8 radioChan, const quint16
// Per channel chunk size.
this->chunkSize = (this->nativeSampleRate / 50);
qInfo(logAudio()) << (isInput ? "Input" : "Output") << QString::fromStdString(info.name) << "(" << aParams.deviceId << ") successfully probed";
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << QString::fromStdString(info.name) << "(" << aParams.deviceId << ") successfully probed";
if (info.nativeFormats == 0)
{
qInfo(logAudio()) << " No natively supported data formats!";
@ -121,9 +150,9 @@ bool audioHandler::init(const quint8 bits, const quint8 radioChan, const quint16
(info.nativeFormats & RTAUDIO_FLOAT64 ? "64-bit float," : "");
qInfo(logAudio()) << " Preferred sample rate:" << info.preferredSampleRate;
if (isInput) {
if (setup.isinput) {
devChannels = info.inputChannels;
}
}
else {
devChannels = info.outputChannels;
}
@ -134,60 +163,119 @@ bool audioHandler::init(const quint8 bits, const quint8 radioChan, const quint16
aParams.nChannels = devChannels;
}
qInfo(logAudio()) << " chunkSize: " << chunkSize;
qInfo(logAudio()) << " chunkSize: " << chunkSize;
try {
if (setup.isinput) {
audio->openStream(NULL, &aParams, RTAUDIO_SINT16, nativeSampleRate, &this->chunkSize, &staticWrite, this, &options);
}
else {
audio->openStream(&aParams, NULL, RTAUDIO_SINT16, this->nativeSampleRate, &this->chunkSize, &staticRead, this, &options);
}
audio->startStream();
isInitialized = true;
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "device successfully opened";
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "detected latency:" << audio->getStreamLatency();
}
catch (RtAudioError& e) {
qInfo(logAudio()) << "Error opening:" << QString::fromStdString(e.getMessage());
}
}
else
{
qCritical(logAudio()) << (isInput ? "Input" : "Output") << QString::fromStdString(info.name) << "(" << aParams.deviceId << ") could not be probed, check audio configuration!";
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << QString::fromStdString(info.name) << "(" << aParams.deviceId << ") could not be probed, check audio configuration!";
}
#elif defined(PORTAUDIO)
#else
format.setSampleSize(16);
format.setChannelCount(2);
format.setSampleRate(INTERNAL_SAMPLE_RATE);
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
if (setup.port.isNull())
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "No audio device was found. You probably need to install libqt5multimedia-plugins.";
return false;
}
int resample_error = 0;
#if !defined(Q_OS_MACX)
options.flags = ((!RTAUDIO_HOG_DEVICE) | (RTAUDIO_MINIMIZE_LATENCY));
#endif
if (isInput) {
resampler = wf_resampler_init(devChannels, nativeSampleRate, samplerate, resampleQuality, &resample_error);
try {
audio->openStream(NULL, &aParams, RTAUDIO_SINT16, nativeSampleRate, &this->chunkSize, &staticWrite, this, &options);
audio->startStream();
isInitialized = true;
}
catch (RtAudioError& e) {
qInfo(logAudio()) << "Error opening:" << QString::fromStdString(e.getMessage());
return false;
}
}
else
else if (!setup.port.isFormatSupported(format))
{
resampler = wf_resampler_init(devChannels, samplerate, this->nativeSampleRate, resampleQuality, &resample_error);
try {
audio->openStream(&aParams, NULL, RTAUDIO_SINT16, this->nativeSampleRate, &this->chunkSize, &staticRead, this, &options);
audio->startStream();
isInitialized = true;
}
catch (RtAudioError& e) {
qInfo(logAudio()) << "Error opening:" << QString::fromStdString(e.getMessage());
return false;
}
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Format not supported, choosing nearest supported format - which may not work!";
format=setup.port.nearestFormat(format);
}
qInfo(logAudio()) << (isInput ? "Input" : "Output") << "device successfully opened";
if (format.channelCount() > 2) {
format.setChannelCount(2);
}
devChannels = format.channelCount();
nativeSampleRate = format.sampleRate();
// chunk size is always relative to Internal Sample Rate.
this->chunkSize = (nativeSampleRate / 50);
qInfo(logAudio()) << (isInput ? "Input" : "Output") << "detected latency:" <<audio->getStreamLatency();
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Internal: sample rate" << format.sampleRate() << "channel count" << format.channelCount();
// We "hopefully" now have a valid format that is supported so try connecting
if (setup.isinput) {
audioInput = new QAudioInput(setup.port, format, this);
connect(audioInput, SIGNAL(notify()), SLOT(notified()));
connect(audioInput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State)));
isInitialized = true;
}
else {
audioOutput = new QAudioOutput(setup.port, format, this);
connect(audioOutput, SIGNAL(notify()), SLOT(notified()));
connect(audioOutput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State)));
isInitialized = true;
}
#endif
// Setup resampler if it is needed.
int resample_error = 0;
if (setup.isinput) {
resampler = wf_resampler_init(devChannels, nativeSampleRate, setup.samplerate, setup.resampleQuality, &resample_error);
}
else {
resampler = wf_resampler_init(devChannels, setup.samplerate, this->nativeSampleRate, setup.resampleQuality, &resample_error);
}
wf_resampler_get_ratio(resampler, &ratioNum, &ratioDen);
qInfo(logAudio()) << (isInput ? "Input" : "Output") << "wf_resampler_init() returned: " << resample_error << " ratioNum" << ratioNum << " ratioDen" << ratioDen;
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "wf_resampler_init() returned: " << resample_error << " ratioNum" << ratioNum << " ratioDen" << ratioDen;
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "thread id" << QThread::currentThreadId();
if (isInitialized) {
this->start();
}
qInfo(logAudio()) << (isInput ? "Input" : "Output") << "thread id" << QThread::currentThreadId();
return isInitialized;
}
void audioHandler::start()
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "start() running";
if ((audioOutput == Q_NULLPTR || audioOutput->state() != QAudio::StoppedState) &&
(audioInput == Q_NULLPTR || audioInput->state() != QAudio::StoppedState)) {
return;
}
if (setup.isinput) {
this->open(QIODevice::WriteOnly | QIODevice::Unbuffered);
//this->open(QIODevice::WriteOnly);
audioInput->start(this);
}
else {
this->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
//this->open(QIODevice::ReadOnly);
audioOutput->start(this);
}
}
void audioHandler::setVolume(unsigned char volume)
{
this->volume = (qreal)volume/255.0;
qInfo(logAudio()) << (isInput ? "Input" : "Output") << "setVolume: " << volume << "(" << this->volume << ")";
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "setVolume: " << volume << "(" << this->volume << ")";
}
@ -198,17 +286,22 @@ void audioHandler::setVolume(unsigned char volume)
/// <param name="data"></param>
/// <param name="maxlen"></param>
/// <returns></returns>
#if defined(RTAUDIO)
int audioHandler::readData(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status)
{
Q_UNUSED(inputBuffer);
Q_UNUSED(streamTime);
// Calculate output length, always full samples
int sentlen = 0;
quint8* buffer = (quint8*)outputBuffer;
if (status == RTAUDIO_OUTPUT_UNDERFLOW)
qDebug(logAudio()) << "Underflow detected";
int nBytes = nFrames * devChannels * 2; // This is ALWAYS 2 bytes per sample and 2 channels
quint8* buffer = (quint8*)outputBuffer;
#elif defined(PORTAUDIO)
#else
qint64 audioHandler::readData(char* buffer, qint64 nBytes)
{
#endif
// Calculate output length, always full samples
int sentlen = 0;
if (ringBuf->size()>0)
{
@ -241,7 +334,7 @@ int audioHandler::readData(void* outputBuffer, void* inputBuffer, unsigned int n
}
if (currentLatency > (int)audioLatency) {
qInfo(logAudio()) << (isInput ? "Input" : "Output") << "Packet " << hex << packet.seq <<
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Packet " << hex << packet.seq <<
" arrived too late (increase output latency!) " <<
dec << packet.time.msecsTo(QTime::currentTime()) << "ms";
lastSeq = packet.seq;
@ -263,10 +356,10 @@ int audioHandler::readData(void* outputBuffer, void* inputBuffer, unsigned int n
}
if (packet.seq <= lastSeq) {
qDebug(logAudio()) << (isInput ? "Input" : "Output") << "Duplicate/early audio packet: " << hex << lastSeq << " got " << hex << packet.seq;
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Duplicate/early audio packet: " << hex << lastSeq << " got " << hex << packet.seq;
}
else if (packet.seq != lastSeq + 1) {
qDebug(logAudio()) << (isInput ? "Input" : "Output") << "Missing audio packet(s) from: " << hex << lastSeq + 1 << " to " << hex << packet.seq - 1;
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Missing audio packet(s) from: " << hex << lastSeq + 1 << " to " << hex << packet.seq - 1;
}
lastSeq = packet.seq;
}
@ -277,18 +370,28 @@ int audioHandler::readData(void* outputBuffer, void* inputBuffer, unsigned int n
if (nBytes > sentlen) {
memset(buffer+sentlen,0,nBytes-sentlen);
}
#if defined(RTAUDIO)
return 0;
#elif defined(PORTAUDIO)
#else
return nBytes;
#endif
}
#if defined(RTAUDIO)
int audioHandler::writeData(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status)
{
Q_UNUSED(outputBuffer);
Q_UNUSED(streamTime);
Q_UNUSED(status);
int sentlen = 0;
int nBytes = nFrames * devChannels * 2; // This is ALWAYS 2 bytes per sample
int nBytes = nFrames * devChannels * 2; // This is ALWAYS 2 bytes per sample and 2 channels
const char* data = (const char*)inputBuffer;
#elif defined(PORTAUDIO)
#else
qint64 audioHandler::writeData(const char* data, qint64 nBytes)
{
#endif
int sentlen = 0;
//qDebug(logAudio()) << "nFrames" << nFrames << "nBytes" << nBytes;
while (sentlen < nBytes) {
if (tempBuf.sent != nBytes)
@ -314,8 +417,12 @@ int audioHandler::writeData(void* outputBuffer, void* inputBuffer, unsigned int
}
//qDebug(logAudio()) << "sentlen" << sentlen;
return 0;
#if defined(RTAUDIO)
return 0;
#elif defined(PORTAUDIO)
#else
return nBytes;
#endif
}
@ -325,21 +432,21 @@ void audioHandler::incomingAudio(audioPacket inPacket)
// Regardless of the radio stream format, the buffered audio will ALWAYS be
// 16bit sample interleaved stereo 48K (or whatever the native sample rate is)
if (!isInitialized || !audio->isStreamRunning())
if (!isInitialized)
{
qDebug(logAudio()) << "Packet received before stream was started";
return;
}
//qDebug(logAudio()) << "Got" << radioSampleBits << "bits, length" << inPacket.data.length();
// Incoming data is 8bits?
if (radioSampleBits == 8)
if (setup.bits == 8)
{
// Current packet is 8bit so need to create a new buffer that is 16bit
QByteArray outPacket((int)inPacket.data.length() * 2 *(devChannels/radioChannels), (char)0xff);
QByteArray outPacket((int)inPacket.data.length() * 2 *(devChannels/setup.radioChan), (char)0xff);
qint16* out = (qint16*)outPacket.data();
for (int f = 0; f < inPacket.data.length(); f++)
{
for (int g = radioChannels; g <= devChannels; g++)
for (int g = setup.radioChan; g <= devChannels; g++)
{
if (isUlaw)
*out++ = ulaw_decode[(quint8)inPacket.data[f]] * this->volume;
@ -353,7 +460,7 @@ void audioHandler::incomingAudio(audioPacket inPacket)
else
{
// This is already a 16bit stream, do we need to convert to stereo?
if (radioChannels == 1 && devChannels > 1) {
if (setup.radioChan == 1 && devChannels > 1) {
// Yes
QByteArray outPacket(inPacket.data.length() * 2, (char)0xff); // Preset the output buffer size.
qint16* in = (qint16*)inPacket.data.data();
@ -398,7 +505,7 @@ void audioHandler::incomingAudio(audioPacket inPacket)
int err = 0;
err = wf_resampler_process_interleaved_int(resampler, in, &inFrames, out, &outFrames);
if (err) {
qInfo(logAudio()) << (isInput ? "Input" : "Output") << "Resampler error " << err << " inFrames:" << inFrames << " outFrames:" << outFrames;
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Resampler error " << err << " inFrames:" << inFrames << " outFrames:" << outFrames;
}
inPacket.data.clear();
inPacket.data = outPacket; // Replace incoming data with converted.
@ -415,7 +522,7 @@ void audioHandler::incomingAudio(audioPacket inPacket)
void audioHandler::changeLatency(const quint16 newSize)
{
qInfo(logAudio()) << (isInput ? "Input" : "Output") << "Changing latency to: " << newSize << " from " << audioLatency;
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Changing latency to: " << newSize << " from " << audioLatency;
audioLatency = newSize;
}
@ -446,7 +553,7 @@ void audioHandler::getNextAudioChunk(QByteArray& ret)
int err = 0;
err = wf_resampler_process_interleaved_int(resampler, in, &inFrames, out, &outFrames);
if (err) {
qInfo(logAudio()) << (isInput ? "Input" : "Output") << "Resampler error " << err << " inFrames:" << inFrames << " outFrames:" << outFrames;
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Resampler error " << err << " inFrames:" << inFrames << " outFrames:" << outFrames;
}
//qInfo(logAudio()) << "Resampler run " << err << " inFrames:" << inFrames << " outFrames:" << outFrames;
//qInfo(logAudio()) << "Resampler run inLen:" << packet->datain.length() << " outLen:" << packet->dataout.length();
@ -457,7 +564,7 @@ void audioHandler::getNextAudioChunk(QByteArray& ret)
//qDebug(logAudio()) << "Now resampled, length" << packet.data.length();
// Do we need to convert mono to stereo?
if (radioChannels == 1 && devChannels > 1)
if (setup.radioChan == 1 && devChannels > 1)
{
// Strip out right channel?
QByteArray outPacket(packet.data.length()/2, (char)0xff);
@ -475,7 +582,7 @@ void audioHandler::getNextAudioChunk(QByteArray& ret)
//qDebug(logAudio()) << "Now mono, length" << packet.data.length();
// Do we need to convert 16-bit to 8-bit?
if (radioSampleBits == 8) {
if (setup.bits == 8) {
QByteArray outPacket((int)packet.data.length() / 2, (char)0xff);
qint16* in = (qint16*)packet.data.data();
for (int f = 0; f < outPacket.length(); f++)
@ -506,4 +613,74 @@ void audioHandler::getNextAudioChunk(QByteArray& ret)
}
qint64 audioHandler::bytesAvailable() const
{
return 0;
}
bool audioHandler::isSequential() const
{
return true;
}
void audioHandler::notified()
{
}
void audioHandler::stateChanged(QAudio::State state)
{
// Process the state
switch (state)
{
case QAudio::IdleState:
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Audio now in idle state: " << audioBuffer.size() << " packets in buffer";
if (audioOutput != Q_NULLPTR && audioOutput->error() == QAudio::UnderrunError)
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "buffer underrun";
//audioOutput->suspend();
}
break;
}
case QAudio::ActiveState:
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Audio now in active state: " << audioBuffer.size() << " packets in buffer";
break;
}
case QAudio::SuspendedState:
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Audio now in suspended state: " << audioBuffer.size() << " packets in buffer";
break;
}
case QAudio::StoppedState:
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Audio now in stopped state: " << audioBuffer.size() << " packets in buffer";
break;
}
default: {
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Unhandled audio state: " << audioBuffer.size() << " packets in buffer";
}
}
}
void audioHandler::stop()
{
if (audioOutput != Q_NULLPTR && audioOutput->state() != QAudio::StoppedState) {
// Stop audio output
audioOutput->stop();
this->stop();
this->close();
}
if (audioInput != Q_NULLPTR && audioInput->state() != QAudio::StoppedState) {
// Stop audio output
audioInput->stop();
this->stop();
this->close();
}
}

Wyświetl plik

@ -7,7 +7,18 @@
#include <QMutex>
#include <QtEndian>
#include <QtMath>
#include "rtaudio/RtAudio.h"
#if defined(RTAUDIO)
#include "RtAudio.h"
#elif defined (PORTAUDIO)
#include "portaudio.h"
#else
#include <QAudioOutput>
#include <QAudioFormat>
#include <QAudioDeviceInfo>
#include <QAudioInput>
#include <QIODevice>
#endif
typedef signed short MY_TYPE;
#define FORMAT RTAUDIO_SINT16
@ -39,7 +50,30 @@ struct audioPacket {
QByteArray data;
};
struct audioSetup {
QString name;
quint8 bits;
quint8 radioChan;
quint16 samplerate;
quint16 latency;
quint8 codec;
bool ulaw;
bool isinput;
#if defined(RTAUDIO)
int port;
#elif defined(PORTAUDIO)
#else
QAudioDeviceInfo port;
#endif
quint8 resampleQuality;
};
// For QtMultimedia, use a native QIODevice
#if !defined(PORTAUDIO) && !defined(RTAUDIO)
class audioHandler : public QIODevice
#else
class audioHandler : public QObject
#endif
{
Q_OBJECT
@ -49,14 +83,26 @@ public:
int getLatency();
bool setDevice(QAudioDeviceInfo deviceInfo);
void start();
void flush();
void stop();
qint64 bytesAvailable() const;
bool isSequential() const;
void getNextAudioChunk(QByteArray &data);
private slots:
bool init(const quint8 bits, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isulaw, const bool isinput, int port, quint8 resampleQuality);
public slots:
bool init(audioSetup setup);
void changeLatency(const quint16 newSize);
void setVolume(unsigned char volume);
void incomingAudio(const audioPacket data);
private slots:
void notified();
void stateChanged(QAudio::State state);
signals:
void audioMessage(QString message);
void sendLatency(quint16 newSize);
@ -64,6 +110,8 @@ signals:
private:
#if defined(RTAUDIO)
int readData(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status);
static int staticRead(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void* userData) {
@ -75,16 +123,29 @@ private:
static int staticWrite(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void* userData) {
return static_cast<audioHandler*>(userData)->writeData(outputBuffer, inputBuffer, nFrames, streamTime, status);
}
#elif defined(PORTAUDIO)
#else
qint64 readData(char* data, qint64 nBytes);
qint64 writeData(const char* data, qint64 nBytes);
#endif
void reinit();
bool isInitialized=false;
#if defined(RTAUDIO)
RtAudio* audio = Q_NULLPTR;
int audioDevice = 0;
RtAudio::StreamParameters aParams;
RtAudio::StreamOptions options;
RtAudio::DeviceInfo info;
#elif defined(PORTAUDIO)
#else
QAudioOutput* audioOutput=Q_NULLPTR;
QAudioInput* audioInput=Q_NULLPTR;
QAudioFormat format;
QAudioDeviceInfo deviceInfo;
#endif
SpeexResamplerState* resampler = Q_NULLPTR;
bool isUlaw;
@ -93,11 +154,11 @@ private:
unsigned int chunkSize;
bool chunkAvailable;
quint32 lastSeq;
quint32 lastSeq;
quint16 radioSampleRate;
quint16 nativeSampleRate=0;
quint8 radioSampleBits;
quint16 radioSampleRate;
quint16 nativeSampleRate=0;
quint8 radioSampleBits;
quint8 radioChannels;
QMap<quint32, audioPacket>audioBuffer;
@ -106,11 +167,13 @@ private:
unsigned int ratioDen;
wilt::Ring<audioPacket> *ringBuf=Q_NULLPTR;
volatile bool ready = false;
audioPacket tempBuf;
quint16 currentLatency;
qreal volume=1.0;
int devChannels;
audioSetup setup;
};
#endif // AUDIOHANDLER_H

Wyświetl plik

@ -74,7 +74,7 @@ void rigCommander::commSetup(unsigned char rigCivAddr, QString rigSerialPort, qu
}
void rigCommander::commSetup(unsigned char rigCivAddr, udpPreferences prefs, QString vsp)
void rigCommander::commSetup(unsigned char rigCivAddr, udpPreferences prefs, audioSetup rxSetup, audioSetup txSetup, QString vsp)
{
// construct
// TODO: Bring this parameter and the comm port from the UI.
@ -90,7 +90,7 @@ void rigCommander::commSetup(unsigned char rigCivAddr, udpPreferences prefs, QSt
if (udp == Q_NULLPTR) {
udp = new udpHandler(prefs);
udp = new udpHandler(prefs,rxSetup,txSetup);
udpHandlerThread = new QThread(this);

Wyświetl plik

@ -88,7 +88,7 @@ public:
public slots:
void process();
void commSetup(unsigned char rigCivAddr, QString rigSerialPort, quint32 rigBaudRate,QString vsp);
void commSetup(unsigned char rigCivAddr, udpPreferences prefs, QString vsp);
void commSetup(unsigned char rigCivAddr, udpPreferences prefs, audioSetup rxSetup, audioSetup txSetup, QString vsp);
void closeComm();
// Power:

Wyświetl plik

@ -4,28 +4,22 @@
#include "udphandler.h"
#include "logcategories.h"
udpHandler::udpHandler(udpPreferences prefs) :
udpHandler::udpHandler(udpPreferences prefs,audioSetup rx, audioSetup tx) :
controlPort(prefs.controlLANPort),
civPort(0),
audioPort(0),
rxSampleRate(prefs.audioRXSampleRate),
txSampleRate(prefs.audioRXSampleRate),
rxLatency(prefs.audioRXLatency),
txLatency(prefs.audioTXLatency),
rxCodec(prefs.audioRXCodec),
txCodec(prefs.audioTXCodec),
audioInputPort(prefs.audioInput),
audioOutputPort(prefs.audioOutput),
resampleQuality(prefs.resampleQuality)
rxSetup(rx),
txSetup(tx)
{
this->port = this->controlPort;
this->username = prefs.username;
this->password = prefs.password;
this->compName = prefs.clientName.mid(0,8) + "-wfview";
qInfo(logUdp()) << "Starting udpHandler user:" << username << " rx latency:" << rxLatency << " tx latency:" << txLatency << " rx sample rate: " << rxSampleRate <<
" rx codec: " << rxCodec << " tx sample rate: " << txSampleRate << " tx codec: " << txCodec;
qInfo(logUdp()) << "Starting udpHandler user:" << username << " rx latency:" << rxSetup.latency << " tx latency:" << txSetup.latency << " rx sample rate: " << rxSetup.samplerate <<
" rx codec: " << rxSetup.codec << " tx sample rate: " << txSetup.samplerate << " tx codec: " << txSetup.codec;
// Try to set the IP address, if it is a hostname then perform a DNS lookup.
if (!radioIP.setAddress(prefs.ipAddress))
@ -190,7 +184,7 @@ void udpHandler::dataReceived()
}
QString tempLatency;
if (rxLatency > audio->audioLatency)
if (rxSetup.latency > audio->audioLatency)
{
tempLatency = QString("%1 ms").arg(audio->audioLatency,3);
}
@ -324,10 +318,11 @@ void udpHandler::dataReceived()
// TX is not supported
if (txSampleRates <2 ) {
txSampleRate = 0;
txCodec = 0;
txSetup.samplerate = 0;
txSetup.codec = 0;
}
audio = new udpAudio(localIP, radioIP, audioPort, rxLatency, txLatency, rxSampleRate, rxCodec, txSampleRate, txCodec, audioOutputPort, audioInputPort,resampleQuality);
audio = new udpAudio(localIP, radioIP, audioPort, rxSetup, txSetup);
QObject::connect(civ, SIGNAL(receive(QByteArray)), this, SLOT(receiveFromCivStream(QByteArray)));
QObject::connect(audio, SIGNAL(haveAudioData(audioPacket)), this, SLOT(receiveAudioData(audioPacket)));
@ -425,15 +420,15 @@ void udpHandler::sendRequestStream()
p.rxenable = 1;
if (this->txSampleRates > 1) {
p.txenable = 1;
p.txcodec = txCodec;
p.txcodec = txSetup.codec;
}
p.rxcodec = rxCodec;
p.rxcodec = rxSetup.codec;
memcpy(&p.username, usernameEncoded.constData(), usernameEncoded.length());
p.rxsample = qToBigEndian((quint32)rxSampleRate);
p.txsample = qToBigEndian((quint32)txSampleRate);
p.rxsample = qToBigEndian((quint32)rxSetup.samplerate);
p.txsample = qToBigEndian((quint32)txSetup.samplerate);
p.civport = qToBigEndian((quint32)civPort);
p.audioport = qToBigEndian((quint32)audioPort);
p.txbuffer = qToBigEndian((quint32)txLatency);
p.txbuffer = qToBigEndian((quint32)txSetup.latency);
p.convert = 1;
sendTrackedPacket(QByteArray::fromRawData((const char*)p.packet, sizeof(p)));
return;
@ -699,18 +694,12 @@ void udpCivData::dataReceived()
// Audio stream
udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint16 rxlatency, quint16 txlatency, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec, int outputPort, int inputPort, quint8 resampleQuality)
udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, audioSetup rxSetup, audioSetup txSetup)
{
qInfo(logUdp()) << "Starting udpAudio";
this->localIP = local;
this->port = audioPort;
this->radioIP = ip;
this->rxLatency = rxlatency;
this->txLatency = txlatency;
this->rxSampleRate = rxsample;
this->txSampleRate = txsample;
this->rxCodec = rxcodec;
this->txCodec = txcodec;
if (txSampleRate == 0) {
enableTx = false;
@ -720,27 +709,6 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint
QUdpSocket::connect(udp, &QUdpSocket::readyRead, this, &udpAudio::dataReceived);
/*
0x72 is RX audio codec
0x73 is TX audio codec (only single channel options)
0x01 uLaw 1ch 8bit
0x02 PCM 1ch 8bit
0x04 PCM 1ch 16bit
0x08 PCM 2ch 8bit
0x10 PCM 2ch 16bit
0x20 uLaw 2ch 8bit
*/
if (rxCodec == 0x01 || rxCodec == 0x20) {
rxIsUlawCodec = true;
}
if (rxCodec == 0x08 || rxCodec == 0x10 || rxCodec == 0x20) {
rxChannelCount = 2;
}
if (rxCodec == 0x04 || rxCodec == 0x10) {
rxNumSamples = 16;
}
rxaudio = new audioHandler();
rxAudioThread = new QThread(this);
@ -748,7 +716,7 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint
rxAudioThread->start();
connect(this, SIGNAL(setupRxAudio(quint8,quint8,quint16,quint16,bool,bool,int,quint8)), rxaudio, SLOT(init(quint8,quint8,quint16,quint16,bool,bool,int,quint8)));
connect(this, SIGNAL(setupRxAudio(audioSetup)), rxaudio, SLOT(init(audioSetup)));
// signal/slot not currently used.
connect(this, SIGNAL(haveAudioData(audioPacket)), rxaudio, SLOT(incomingAudio(audioPacket)));
@ -756,13 +724,7 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint
connect(this, SIGNAL(haveSetVolume(unsigned char)), rxaudio, SLOT(setVolume(unsigned char)));
connect(rxAudioThread, SIGNAL(finished()), rxaudio, SLOT(deleteLater()));
if (txCodec == 0x01)
txIsUlawCodec = true;
else if (txCodec == 0x04)
txNumSamples = 16;
txChannelCount = 1; // Only 1 channel is supported.
txSetup.radioChan = 1;
txaudio = new audioHandler();
txAudioThread = new QThread(this);
@ -771,7 +733,7 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint
txAudioThread->start();
connect(this, SIGNAL(setupTxAudio(quint8,quint8,quint16,quint16,bool,bool,int,quint8)), txaudio, SLOT(init(quint8,quint8,quint16,quint16,bool,bool,int,quint8)));
connect(this, SIGNAL(setupTxAudio(audioSetup)), txaudio, SLOT(init(audioSetup)));
connect(txAudioThread, SIGNAL(finished()), txaudio, SLOT(deleteLater()));
@ -782,10 +744,10 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint
pingTimer->start(PING_PERIOD); // send ping packets every 100ms
if (enableTx) {
emit setupTxAudio(txNumSamples, txChannelCount, txSampleRate, txLatency, txIsUlawCodec, true, inputPort, resampleQuality);
emit setupTxAudio(txSetup);
}
emit setupRxAudio(rxNumSamples, rxChannelCount, rxSampleRate, txLatency, rxIsUlawCodec, false, outputPort,resampleQuality);
emit setupRxAudio(rxSetup);
watchdogTimer = new QTimer();
connect(watchdogTimer, &QTimer::timeout, this, &udpAudio::watchdog);

Wyświetl plik

@ -174,7 +174,7 @@ class udpAudio : public udpBase
Q_OBJECT
public:
udpAudio(QHostAddress local, QHostAddress ip, quint16 aport, quint16 rxlatency, quint16 txlatency, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec, int outputPort, int inputPort, quint8 resampleQuality);
udpAudio(QHostAddress local, QHostAddress ip, quint16 aport, audioSetup rxSetup, audioSetup txSetup);
~udpAudio();
int audioLatency = 0;
@ -182,8 +182,8 @@ public:
signals:
void haveAudioData(audioPacket data);
void setupTxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, int port, quint8 resampleQuality);
void setupRxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, int port, quint8 resampleQuality);
void setupTxAudio(audioSetup setup);
void setupRxAudio(audioSetup setup);
void haveChangeLatency(quint16 value);
void haveSetVolume(unsigned char value);
@ -233,7 +233,7 @@ class udpHandler: public udpBase
Q_OBJECT
public:
udpHandler(udpPreferences prefs);
udpHandler(udpPreferences prefs, audioSetup rxAudio, audioSetup txAudio);
~udpHandler();
bool streamOpened = false;
@ -282,17 +282,8 @@ private:
quint16 civPort;
quint16 audioPort;
quint16 rxSampleRate;
quint16 txSampleRate;
quint16 rxLatency;
quint16 txLatency;
quint8 rxCodec;
quint8 txCodec;
int audioInputPort;
int audioOutputPort;
quint8 resampleQuality;
audioSetup rxSetup;
audioSetup txSetup;
quint16 reauthInterval = 60000;
QString devName;

Wyświetl plik

@ -367,6 +367,10 @@ void udpServer::controlReceived()
if (!config.lan) {
// Radio is connected by USB/Serial and we assume that audio is connected as well.
// Create audio TX/RX threads if they don't already exist (first client chooses samplerate/codec)
audioSetup setup;
setup.resampleQuality = config.resampleQuality;
if (txaudio == Q_NULLPTR)
{
bool uLaw = false;
@ -385,6 +389,13 @@ void udpServer::controlReceived()
samples = 16;
}
//setup.port = config.audioOutput;
setup.bits = samples;
setup.radioChan = channels;
setup.ulaw = uLaw;
setup.samplerate = current->txSampleRate;
setup.latency = current->txBufferLen;
setup.isinput = false;
txaudio = new audioHandler();
txAudioThread = new QThread(this);
@ -392,10 +403,11 @@ void udpServer::controlReceived()
txAudioThread->start();
connect(this, SIGNAL(setupTxAudio(quint8, quint8, quint16, quint16, bool, bool, int, quint8)), txaudio, SLOT(init(quint8, quint8, quint16, quint16, bool, bool, int, quint8)));
connect(this, SIGNAL(setupTxAudio(audioSetup)), txaudio, SLOT(init(audioSetup)));
connect(txAudioThread, SIGNAL(finished()), txaudio, SLOT(deleteLater()));
emit setupTxAudio(samples, channels, current->txSampleRate, current->txBufferLen, uLaw, false, config.audioOutput, config.resampleQuality);
emit setupTxAudio(setup);
hasTxAudio = datagram.senderAddress();
connect(this, SIGNAL(haveAudioData(audioPacket)), txaudio, SLOT(incomingAudio(audioPacket)));
@ -419,16 +431,24 @@ void udpServer::controlReceived()
samples = 16;
}
rxaudio = new audioHandler();
rxAudioThread = new QThread(this);
rxaudio->moveToThread(rxAudioThread);
rxAudioThread->start();
connect(this, SIGNAL(setupRxAudio(quint8, quint8, quint16, quint16, bool, bool, int, quint8)), rxaudio, SLOT(init(quint8, quint8, quint16, quint16, bool, bool, int, quint8)));
connect(this, SIGNAL(setupRxAudio(audioSetup)), rxaudio, SLOT(init(audioSetup)));
connect(rxAudioThread, SIGNAL(finished()), rxaudio, SLOT(deleteLater()));
emit setupRxAudio(samples, channels, current->rxSampleRate, 250, uLaw, true, config.audioInput, config.resampleQuality);
setup.bits = samples;
setup.radioChan = channels;
setup.ulaw = uLaw;
setup.samplerate = current->rxSampleRate;
setup.latency = 150;
setup.isinput = true;
//setup.port = config.audioInput;
setup.resampleQuality = config.resampleQuality;
emit setupRxAudio(setup);
rxAudioTimer = new QTimer();
rxAudioTimer->setTimerType(Qt::PreciseTimer);

Wyświetl plik

@ -52,8 +52,8 @@ signals:
void haveDataFromServer(QByteArray);
void haveAudioData(audioPacket data);
void setupTxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, int device, quint8 resampleQuality);
void setupRxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, int device, quint8 resampleQuality);
void setupTxAudio(audioSetup);
void setupRxAudio(audioSetup);

Wyświetl plik

@ -40,6 +40,7 @@ wfmain::wfmain(const QString serialPortCL, const QString hostCL, const QString s
qRegisterMetaType<spectrumMode>();
qRegisterMetaType<freqt>();
qRegisterMetaType<audioPacket>();
qRegisterMetaType <audioSetup>();
haveRigCaps = false;
@ -154,7 +155,8 @@ void wfmain::openRig()
if (prefs.enableLAN)
{
ui->lanEnableBtn->setChecked(true);
emit sendCommSetup(prefs.radioCIVAddr, udpPrefs,prefs.virtualSerialPort);
// We need to setup the tx/rx audio:
emit sendCommSetup(prefs.radioCIVAddr, udpPrefs, rxSetup, txSetup, prefs.virtualSerialPort);
} else {
ui->serialEnableBtn->setChecked(true);
if( (prefs.serialPortRadio.toLower() == QString("auto")) && (serialPortCL.isEmpty()))
@ -352,7 +354,7 @@ void wfmain::makeRig()
connect(rig, SIGNAL(haveStatusUpdate(QString)), this, SLOT(receiveStatusUpdate(QString)));
// Rig comm setup:
connect(this, SIGNAL(sendCommSetup(unsigned char, udpPreferences, QString)), rig, SLOT(commSetup(unsigned char, udpPreferences, QString)));
connect(this, SIGNAL(sendCommSetup(unsigned char, udpPreferences, audioSetup, audioSetup, QString)), rig, SLOT(commSetup(unsigned char, udpPreferences, audioSetup, audioSetup, QString)));
connect(this, SIGNAL(sendCommSetup(unsigned char, QString, quint32,QString)), rig, SLOT(commSetup(unsigned char, QString, quint32,QString)));
@ -763,6 +765,7 @@ void wfmain::setServerToPrefs()
if (serverConfig.enabled) {
serverConfig.lan = prefs.enableLAN;
if (!serverConfig.lan) {
// How do we setup the audio for server????
serverConfig.resampleQuality = udpPrefs.resampleQuality;
serverConfig.audioInput = udpPrefs.audioInput;
serverConfig.audioOutput = udpPrefs.audioOutput;
@ -809,6 +812,8 @@ void wfmain::setUIToPrefs()
void wfmain::setAudioDevicesUI()
{
#if defined(RTAUDIO)
#if defined(Q_OS_LINUX)
RtAudio* audio = new RtAudio(RtAudio::Api::LINUX_ALSA);
#elif defined(Q_OS_WIN)
@ -860,6 +865,22 @@ void wfmain::setAudioDevicesUI()
}
delete audio;
#elif defined(PORTAUDIO)
// Use PortAudio device enumeration
#else
// If no external library is configured, use QTMultimedia
// Enumerate audio devices, need to do before settings are loaded.
const auto audioOutputs = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
for (const QAudioDeviceInfo& deviceInfo : audioOutputs) {
ui->audioOutputCombo->addItem(deviceInfo.deviceName(), QVariant::fromValue(deviceInfo));
}
const auto audioInputs = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
for (const QAudioDeviceInfo& deviceInfo : audioInputs) {
ui->audioInputCombo->addItem(deviceInfo.deviceName(), QVariant::fromValue(deviceInfo));
}
#endif
}
void wfmain::setSerialDevicesUI()
@ -1204,24 +1225,28 @@ void wfmain::loadSettings()
ui->passwordTxt->setEnabled(ui->lanEnableBtn->isChecked());
ui->passwordTxt->setText(QString("%1").arg(udpPrefs.password));
rxSetup.isinput = false;
txSetup.isinput = true;
udpPrefs.audioRXLatency = settings->value("AudioRXLatency", udpDefPrefs.audioRXLatency).toInt();
rxSetup.latency = settings->value("AudioRXLatency", "150").toInt();
ui->rxLatencySlider->setEnabled(ui->lanEnableBtn->isChecked());
ui->rxLatencySlider->setValue(udpPrefs.audioRXLatency);
ui->rxLatencySlider->setValue(rxSetup.latency);
ui->rxLatencySlider->setTracking(false); // Stop it sending value on every change.
udpPrefs.audioTXLatency = settings->value("AudioTXLatency", udpDefPrefs.audioTXLatency).toInt();
txSetup.latency = settings->value("AudioTXLatency", "150").toInt();
ui->txLatencySlider->setEnabled(ui->lanEnableBtn->isChecked());
ui->txLatencySlider->setValue(udpPrefs.audioTXLatency);
ui->txLatencySlider->setValue(rxSetup.latency);
ui->txLatencySlider->setTracking(false); // Stop it sending value on every change.
udpPrefs.audioRXSampleRate = settings->value("AudioRXSampleRate", udpDefPrefs.audioRXSampleRate).toInt();
udpPrefs.audioTXSampleRate = settings->value("AudioTXSampleRate",udpDefPrefs.audioTXSampleRate).toInt();
ui->audioSampleRateCombo->blockSignals(true);
rxSetup.samplerate = settings->value("AudioRXSampleRate", "48000").toInt();
txSetup.samplerate = rxSetup.samplerate;
ui->audioSampleRateCombo->setEnabled(ui->lanEnableBtn->isChecked());
int audioSampleRateIndex = ui->audioSampleRateCombo->findText(QString::number(udpPrefs.audioRXSampleRate));
int audioSampleRateIndex = ui->audioSampleRateCombo->findText(QString::number(rxSetup.samplerate));
if (audioSampleRateIndex != -1) {
ui->audioSampleRateCombo->setCurrentIndex(audioSampleRateIndex);
}
ui->audioSampleRateCombo->blockSignals(false);
// Add codec combobox items here so that we can add userdata!
ui->audioRXCodecCombo->addItem("LPCM 1ch 16bit", 4);
@ -1231,39 +1256,61 @@ void wfmain::loadSettings()
ui->audioRXCodecCombo->addItem("uLaw 2ch 8bit", 32);
ui->audioRXCodecCombo->addItem("PCM 2ch 8bit", 8);
udpPrefs.audioRXCodec = settings->value("AudioRXCodec", udpDefPrefs.audioRXCodec).toInt();
ui->audioRXCodecCombo->blockSignals(true);
rxSetup.codec = settings->value("AudioRXCodec", "4").toInt();
ui->audioRXCodecCombo->setEnabled(ui->lanEnableBtn->isChecked());
for (int f = 0; f < ui->audioRXCodecCombo->count(); f++)
if (ui->audioRXCodecCombo->itemData(f).toInt() == udpPrefs.audioRXCodec)
if (ui->audioRXCodecCombo->itemData(f).toInt() == rxSetup.codec)
ui->audioRXCodecCombo->setCurrentIndex(f);
ui->audioRXCodecCombo->blockSignals(false);
ui->audioTXCodecCombo->addItem("LPCM 1ch 16bit", 4);
ui->audioTXCodecCombo->addItem("LPCM 1ch 8bit", 2);
ui->audioTXCodecCombo->addItem("uLaw 1ch 8bit", 1);
udpPrefs.audioTXCodec = settings->value("AudioTXCodec", udpDefPrefs.audioTXCodec).toInt();
ui->audioRXCodecCombo->blockSignals(true);
txSetup.codec = settings->value("AudioTXCodec", "4").toInt();
ui->audioTXCodecCombo->setEnabled(ui->lanEnableBtn->isChecked());
for (int f = 0; f < ui->audioTXCodecCombo->count(); f++)
if (ui->audioTXCodecCombo->itemData(f).toInt() == udpPrefs.audioTXCodec)
if (ui->audioTXCodecCombo->itemData(f).toInt() == txSetup.codec)
ui->audioTXCodecCombo->setCurrentIndex(f);
ui->audioRXCodecCombo->blockSignals(false);
udpPrefs.audioOutputName = settings->value("AudioOutput", udpDefPrefs.audioOutputName).toString();
qInfo(logGui()) << "Got Audio Output: " << udpPrefs.audioOutputName;
int audioOutputIndex = ui->audioOutputCombo->findText(udpPrefs.audioOutputName);
ui->audioOutputCombo->blockSignals(true);
rxSetup.name = settings->value("AudioOutput", udpDefPrefs.audioOutputName).toString();
qInfo(logGui()) << "Got Audio Output: " << rxSetup.name;
int audioOutputIndex = ui->audioOutputCombo->findText(rxSetup.name);
if (audioOutputIndex != -1) {
ui->audioOutputCombo->setCurrentIndex(audioOutputIndex);
#if defined(RTAUDIO)
udpPrefs.audioOutput = ui->audioOutputCombo->itemData(audioOutputIndex).toInt();
#elif defined(PORTAUDIO)
#else
QVariant v = ui->audioOutputCombo->currentData();
rxSetup.port = v.value<QAudioDeviceInfo>();
#endif
}
ui->audioOutputCombo->blockSignals(false);
udpPrefs.audioInputName = settings->value("AudioInput", udpDefPrefs.audioInputName).toString();
qInfo(logGui()) << "Got Audio Input: " << udpPrefs.audioInputName;
int audioInputIndex = ui->audioInputCombo->findText(udpPrefs.audioInputName);
ui->audioInputCombo->blockSignals(true);
txSetup.name = settings->value("AudioInput", udpDefPrefs.audioInputName).toString();
qInfo(logGui()) << "Got Audio Input: " << txSetup.name;
int audioInputIndex = ui->audioInputCombo->findText(txSetup.name);
if (audioInputIndex != -1) {
ui->audioInputCombo->setCurrentIndex(audioInputIndex);
#if defined(RTAUDIO)
udpPrefs.audioInput = ui->audioInputCombo->itemData(audioInputIndex).toInt();
#elif defined(PORTAUDIO)
#else
QVariant v = ui->audioInputCombo->currentData();
txSetup.port = v.value<QAudioDeviceInfo>();
#endif
}
ui->audioOutputCombo->blockSignals(false);
rxSetup.resampleQuality = settings->value("ResampleQuality", udpDefPrefs.resampleQuality).toInt();
txSetup.resampleQuality = rxSetup.resampleQuality;
udpPrefs.resampleQuality = settings->value("ResampleQuality", udpDefPrefs.resampleQuality).toInt();
udpPrefs.clientName = settings->value("ClientName", udpDefPrefs.clientName).toString();
settings->endGroup();
@ -1368,15 +1415,15 @@ void wfmain::saveSettings()
settings->setValue("AudioLANPort", udpPrefs.audioLANPort);
settings->setValue("Username", udpPrefs.username);
settings->setValue("Password", udpPrefs.password);
settings->setValue("AudioRXLatency", udpPrefs.audioRXLatency);
settings->setValue("AudioTXLatency", udpPrefs.audioTXLatency);
settings->setValue("AudioRXSampleRate", udpPrefs.audioRXSampleRate);
settings->setValue("AudioRXCodec", udpPrefs.audioRXCodec);
settings->setValue("AudioTXSampleRate", udpPrefs.audioTXSampleRate);
settings->setValue("AudioTXCodec", udpPrefs.audioTXCodec);
settings->setValue("AudioRXLatency", rxSetup.latency);
settings->setValue("AudioTXLatency", txSetup.latency);
settings->setValue("AudioRXSampleRate", rxSetup.samplerate);
settings->setValue("AudioRXCodec", rxSetup.codec);
settings->setValue("AudioTXSampleRate", txSetup.samplerate);
settings->setValue("AudioTXCodec", txSetup.codec);
settings->setValue("AudioOutput", udpPrefs.audioOutputName);
settings->setValue("AudioInput", udpPrefs.audioInputName);
settings->setValue("ResampleQuality", udpPrefs.resampleQuality);
settings->setValue("ResampleQuality", rxSetup.resampleQuality);
settings->setValue("ClientName", udpPrefs.clientName);
settings->endGroup();
@ -3695,28 +3742,30 @@ void wfmain::on_audioSampleRateCombo_currentIndexChanged(QString text)
{
udpPrefs.audioRXSampleRate = text.toInt();
udpPrefs.audioTXSampleRate = text.toInt();
rxSetup.samplerate = text.toInt();
txSetup.samplerate = text.toInt();
}
void wfmain::on_audioRXCodecCombo_currentIndexChanged(int value)
{
udpPrefs.audioRXCodec = ui->audioRXCodecCombo->itemData(value).toInt();
rxSetup.codec = ui->audioRXCodecCombo->itemData(value).toInt();
}
void wfmain::on_audioTXCodecCombo_currentIndexChanged(int value)
{
udpPrefs.audioTXCodec = ui->audioTXCodecCombo->itemData(value).toInt();
txSetup.codec = ui->audioTXCodecCombo->itemData(value).toInt();
}
void wfmain::on_rxLatencySlider_valueChanged(int value)
{
udpPrefs.audioRXLatency = value;
rxSetup.latency = value;
ui->rxLatencyValue->setText(QString::number(value));
emit sendChangeLatency(value);
}
void wfmain::on_txLatencySlider_valueChanged(int value)
{
udpPrefs.audioTXLatency = value;
txSetup.latency = value;
ui->txLatencyValue->setText(QString::number(value));
}

Wyświetl plik

@ -136,7 +136,7 @@ signals:
void sayMode();
void sayAll();
void sendCommSetup(unsigned char rigCivAddr, QString rigSerialPort, quint32 rigBaudRate,QString vsp);
void sendCommSetup(unsigned char rigCivAddr, udpPreferences prefs, QString vsp);
void sendCommSetup(unsigned char rigCivAddr, udpPreferences prefs, audioSetup rxSetup, audioSetup txSetup, QString vsp);
void sendCloseComm();
void sendChangeLatency(quint16 latency);
void initServer();
@ -637,6 +637,10 @@ private:
udpPreferences udpPrefs;
udpPreferences udpDefPrefs;
// Configuration for audio output and input.
audioSetup rxSetup;
audioSetup txSetup;
colors defaultColors;
void setDefaultColors(); // populate with default values
@ -731,6 +735,7 @@ Q_DECLARE_METATYPE(struct freqt)
Q_DECLARE_METATYPE(struct udpPreferences)
Q_DECLARE_METATYPE(struct rigStateStruct)
Q_DECLARE_METATYPE(struct audioPacket)
Q_DECLARE_METATYPE(struct audioSetup)
Q_DECLARE_METATYPE(enum rigInput)
Q_DECLARE_METATYPE(enum meterKind)
Q_DECLARE_METATYPE(enum spectrumMode)

Wyświetl plik

@ -4,7 +4,7 @@
#
#-------------------------------------------------
QT += core gui serialport network
QT += core gui serialport network multimedia
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
@ -90,7 +90,7 @@ CONFIG(debug, release|debug) {
}
#linux:LIBS += -L./ -l$$QCPLIB -lpulse -lpulse-simple -lpthread
linux:LIBS += -L./ -l$$QCPLIB -lrtaudio -lpthread
linux:LIBS += -L./ -l$$QCPLIB
macx:LIBS += -framework CoreAudio -framework CoreFoundation -lpthread
!linux:SOURCES += ../qcustomplot/qcustomplot.cpp rtaudio/RTAudio.cpp