Merge branch 'audio-enhance'

merge-requests/7/head
Roeland Jansen 2021-11-06 13:10:21 +01:00
commit 35cb1ed053
6 zmienionych plików z 208 dodań i 38 usunięć

Wyświetl plik

@ -8,6 +8,10 @@
#include "logcategories.h"
#include "ulaw.h"
#if defined(Q_OS_WIN) && defined(PORTAUDIO)
#include <objbase.h>
#endif
audioHandler::audioHandler(QObject* parent)
{
@ -29,6 +33,7 @@ audioHandler::~audioHandler()
}
delete audio;
#elif defined(PORTAUDIO)
Pa_StopStream(audio);
#else
stop();
#endif
@ -81,7 +86,7 @@ bool audioHandler::init(audioSetup setupIn)
setup.bits = 16;
}
ringBuf = new wilt::Ring<audioPacket>(100); // Should be customizable.
ringBuf = new wilt::Ring<audioPacket>(setupIn.latency / 8 + 1); // Should be customizable.
tempBuf.sent = 0;
@ -124,14 +129,9 @@ bool audioHandler::init(audioSetup setupIn)
if (info.probed)
{
// if "preferred" sample rate is 44100, try 48K instead
if (info.preferredSampleRate == (unsigned int)44100) {
qDebug(logAudio()) << "Preferred sample rate 44100, trying 48000";
this->nativeSampleRate = 48000;
}
else {
this->nativeSampleRate = info.preferredSampleRate;
}
// Always use the "preferred" sample rate
// We can always resample if needed
this->nativeSampleRate = info.preferredSampleRate;
// Per channel chunk size.
this->chunkSize = (this->nativeSampleRate / 50);
@ -189,6 +189,79 @@ bool audioHandler::init(audioSetup setupIn)
#elif defined(PORTAUDIO)
PaError err;
#ifdef Q_OS_WIN
CoInitialize(0);
#endif
memset(&aParams, 0,sizeof(PaStreamParameters));
if (setup.port > 0) {
aParams.device = setup.port;
}
else if (setup.isinput) {
aParams.device = Pa_GetDefaultInputDevice();
}
else {
aParams.device = Pa_GetDefaultOutputDevice();
}
info = Pa_GetDeviceInfo(aParams.device);
aParams.channelCount = 2;
aParams.hostApiSpecificStreamInfo = NULL;
aParams.sampleFormat = paInt16;
aParams.suggestedLatency = info->defaultLowInputLatency;
aParams.hostApiSpecificStreamInfo = NULL;
// Always use the "preferred" sample rate
// We can always resample if needed
this->nativeSampleRate = info->defaultSampleRate;
// Per channel chunk size.
this->chunkSize = (this->nativeSampleRate / 50);
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << info->name << "(" << aParams.device << ") successfully probed";
if (setup.isinput) {
devChannels = info->maxInputChannels;
}
else {
devChannels = info->maxOutputChannels;
}
qInfo(logAudio()) << " Channels:" << devChannels;
if (devChannels > 2) {
devChannels = 2;
}
aParams.channelCount = devChannels;
qInfo(logAudio()) << " chunkSize: " << chunkSize;
if (setup.isinput) {
err=Pa_OpenStream(&audio, &aParams, 0, this->nativeSampleRate, this->chunkSize, paNoFlag, &audioHandler::staticWrite, (void*)this);
//err = Pa_OpenDefaultStream(&audio, 2, 0, paFloat32, this->nativeSampleRate, this->chunkSize, &audioHandler::staticWrite, (void*)this);
}
else {
err=Pa_OpenStream(&audio, 0, &aParams, this->nativeSampleRate, this->chunkSize, paNoFlag, &audioHandler::staticRead, (void*)this);
//err = Pa_OpenDefaultStream(&audio, 0, 2, paFloat32, this->nativeSampleRate, this->chunkSize, &audioHandler::staticRead, (void*)this);
}
if (err == paNoError) {
err = Pa_StartStream(audio);
}
if (err == paNoError) {
isInitialized = true;
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "device successfully opened";
}
else {
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "failed to open device" << Pa_GetErrorText(err);
}
//qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "detected latency:" << audio->getStreamLatency();
#else
format.setSampleSize(16);
@ -293,7 +366,7 @@ void audioHandler::start()
}
if (setup.isinput) {
#ifdef Q_OS_MACX
#ifndef Q_OS_WIN
this->open(QIODevice::WriteOnly);
#else
this->open(QIODevice::WriteOnly | QIODevice::Unbuffered);
@ -301,7 +374,7 @@ void audioHandler::start()
audioInput->start(this);
}
else {
#ifdef Q_OS_MACX
#ifndef Q_OS_WIN
this->open(QIODevice::ReadOnly);
#else
this->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
@ -328,7 +401,8 @@ void audioHandler::setVolume(unsigned char volume)
/// <param name="maxlen"></param>
/// <returns></returns>
#if defined(RTAUDIO)
int audioHandler::readData(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status)
int audioHandler::readData(void* outputBuffer, void* inputBuffer,
unsigned int nFrames, double streamTime, RtAudioStreamStatus status)
{
Q_UNUSED(inputBuffer);
Q_UNUSED(streamTime);
@ -337,6 +411,15 @@ int audioHandler::readData(void* outputBuffer, void* inputBuffer, unsigned int n
int nBytes = nFrames * devChannels * 2; // This is ALWAYS 2 bytes per sample and 2 channels
quint8* buffer = (quint8*)outputBuffer;
#elif defined(PORTAUDIO)
int audioHandler::readData(const void* inputBuffer, void* outputBuffer,
unsigned long nFrames, const PaStreamCallbackTimeInfo * streamTime, PaStreamCallbackFlags status)
{
Q_UNUSED(inputBuffer);
Q_UNUSED(streamTime);
Q_UNUSED(status);
int nBytes = nFrames * devChannels * 2; // This is ALWAYS 2 bytes per sample and 2 channels
quint8* buffer = (quint8*)outputBuffer;
#else
qint64 audioHandler::readData(char* buffer, qint64 nBytes)
{
@ -416,13 +499,15 @@ qint64 audioHandler::readData(char* buffer, qint64 nBytes)
#if defined(RTAUDIO)
return 0;
#elif defined(PORTAUDIO)
return 0;
#else
return nBytes;
#endif
}
#if defined(RTAUDIO)
int audioHandler::writeData(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status)
int audioHandler::writeData(void* outputBuffer, void* inputBuffer,
unsigned int nFrames, double streamTime, RtAudioStreamStatus status)
{
Q_UNUSED(outputBuffer);
Q_UNUSED(streamTime);
@ -430,6 +515,15 @@ int audioHandler::writeData(void* outputBuffer, void* inputBuffer, unsigned int
int nBytes = nFrames * devChannels * 2; // This is ALWAYS 2 bytes per sample and 2 channels
const char* data = (const char*)inputBuffer;
#elif defined(PORTAUDIO)
int audioHandler::writeData(const void* inputBuffer, void* outputBuffer,
unsigned long nFrames, const PaStreamCallbackTimeInfo * streamTime,
PaStreamCallbackFlags status)
{
Q_UNUSED(outputBuffer);
Q_UNUSED(streamTime);
Q_UNUSED(status);
int nBytes = nFrames * devChannels * 2; // This is ALWAYS 2 bytes per sample and 2 channels
const char* data = (const char*)inputBuffer;
#else
qint64 audioHandler::writeData(const char* data, qint64 nBytes)
{
@ -467,6 +561,7 @@ qint64 audioHandler::writeData(const char* data, qint64 nBytes)
#if defined(RTAUDIO)
return 0;
#elif defined(PORTAUDIO)
return 0;
#else
return nBytes;
#endif
@ -591,7 +686,7 @@ void audioHandler::incomingAudio(audioPacket inPacket)
if (!ringBuf->try_write(inPacket))
{
qDebug(logAudio()) << "Buffer full! capacity:" << ringBuf->capacity() << "length" << ringBuf->size();
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Buffer full! capacity:" << ringBuf->capacity() << "length" << ringBuf->size();
}
return;
}
@ -600,6 +695,8 @@ void audioHandler::changeLatency(const quint16 newSize)
{
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Changing latency to: " << newSize << " from " << setup.latency;
setup.latency = newSize;
delete ringBuf;
ringBuf = new wilt::Ring<audioPacket>(setup.latency / 8 + 1); // Should be customizable.
}
int audioHandler::getLatency()
@ -618,13 +715,13 @@ void audioHandler::getNextAudioChunk(QByteArray& ret)
{
currentLatency = packet.time.msecsTo(QTime::currentTime());
while (currentLatency > setup.latency) {
if (currentLatency > setup.latency) {
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Packet " << hex << packet.seq <<
" arrived too late (increase output latency!) " <<
dec << packet.time.msecsTo(QTime::currentTime()) << "ms";
if (!ringBuf->try_read(packet))
break;
currentLatency = packet.time.msecsTo(QTime::currentTime());
// if (!ringBuf->try_read(packet))
// break;
// currentLatency = packet.time.msecsTo(QTime::currentTime());
}
//qDebug(logAudio) << "Chunksize" << this->chunkSize << "Packet size" << packet.data.length();

Wyświetl plik

@ -9,10 +9,14 @@
#include <QtMath>
#if defined(RTAUDIO)
#ifdef Q_OS_WIN
#include "RtAudio.h"
#else
#include "rtaudio/RtAudio.h"
#endif
#elif defined (PORTAUDIO)
#include "portaudio.h"
#error "PORTAUDIO is not currently supported"
//#error "PORTAUDIO is not currently supported"
#else
#include <QAudioOutput>
#include <QAudioFormat>
@ -67,9 +71,8 @@ struct audioSetup {
quint8 codec;
bool ulaw;
bool isinput;
#if defined(RTAUDIO)
#if defined(RTAUDIO) || defined(PORTAUDIO)
int port;
#elif defined(PORTAUDIO)
#else
QAudioDeviceInfo port;
#endif
@ -137,6 +140,21 @@ private:
return static_cast<audioHandler*>(userData)->writeData(outputBuffer, inputBuffer, nFrames, streamTime, status);
}
#elif defined(PORTAUDIO)
int readData(const void* inputBuffer, void* outputBuffer,
unsigned long nFrames,
const PaStreamCallbackTimeInfo* streamTime,
PaStreamCallbackFlags status);
static int staticRead(const void* inputBuffer, void* outputBuffer, unsigned long nFrames, const PaStreamCallbackTimeInfo* streamTime, PaStreamCallbackFlags status, void* userData) {
return ((audioHandler*)userData)->readData(inputBuffer, outputBuffer, nFrames, streamTime, status);
}
int writeData(const void* inputBuffer, void* outputBuffer,
unsigned long nFrames,
const PaStreamCallbackTimeInfo* streamTime,
PaStreamCallbackFlags status);
static int staticWrite(const void* inputBuffer, void* outputBuffer, unsigned long nFrames, const PaStreamCallbackTimeInfo* streamTime, PaStreamCallbackFlags status, void* userData) {
return ((audioHandler*)userData)->writeData(inputBuffer, outputBuffer, nFrames, streamTime, status);
}
#else
qint64 readData(char* data, qint64 nBytes);
@ -154,6 +172,9 @@ private:
RtAudio::StreamOptions options;
RtAudio::DeviceInfo info;
#elif defined(PORTAUDIO)
PaStream* audio = Q_NULLPTR;
PaStreamParameters aParams;
const PaDeviceInfo *info;
#else
QAudioOutput* audioOutput=Q_NULLPTR;
QAudioInput* audioInput=Q_NULLPTR;

Wyświetl plik

@ -346,7 +346,7 @@ void udpHandler::dataReceived()
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)));
//QObject::connect(audio, SIGNAL(haveAudioData(audioPacket)), this, SLOT(receiveAudioData(audioPacket)));
QObject::connect(this, SIGNAL(haveChangeLatency(quint16)), audio, SLOT(changeLatency(quint16)));
QObject::connect(this, SIGNAL(haveSetVolume(unsigned char)), audio, SLOT(setVolume(unsigned char)));
@ -740,7 +740,7 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, audio
connect(this, SIGNAL(setupRxAudio(audioSetup)), rxaudio, SLOT(init(audioSetup)));
// signal/slot not currently used.
connect(this, SIGNAL(haveAudioData(audioPacket)), rxaudio, SLOT(incomingAudio(audioPacket)));
//connect(this, SIGNAL(haveAudioData(audioPacket)), rxaudio, SLOT(incomingAudio(audioPacket)));
connect(this, SIGNAL(haveChangeLatency(quint16)), rxaudio, SLOT(changeLatency(quint16)));
connect(this, SIGNAL(haveSetVolume(unsigned char)), rxaudio, SLOT(setVolume(unsigned char)));
connect(rxAudioThread, SIGNAL(finished()), rxaudio, SLOT(deleteLater()));
@ -945,8 +945,8 @@ void udpAudio::dataReceived()
tempAudio.data = r.mid(0x18);
// Prefer signal/slot to forward audio as it is thread/safe
// Need to do more testing but latency appears fine.
//audioLatency = rxaudio->incomingAudio(tempAudio);
emit haveAudioData(tempAudio);
rxaudio->incomingAudio(tempAudio);
//emit haveAudioData(tempAudio);
audioLatency = rxaudio->getLatency();
}
break;

Wyświetl plik

@ -653,7 +653,9 @@ void udpServer::audioReceived()
tempAudio.sent = 0;
tempAudio.data = r.mid(0x18);
//qInfo(logUdpServer()) << "sending tx audio " << in->seq;
emit haveAudioData(tempAudio);
//emit haveAudioData(tempAudio);
txaudio->incomingAudio(tempAudio);
}
}
break;

Wyświetl plik

@ -106,6 +106,11 @@ wfmain::~wfmain()
delete rpt;
delete ui;
delete settings;
#if defined(PORTAUDIO)
Pa_Terminate();
#endif
}
void wfmain::closeEvent(QCloseEvent *event)
@ -1023,6 +1028,35 @@ void wfmain::setAudioDevicesUI()
#elif defined(PORTAUDIO)
// Use PortAudio device enumeration
PaError err;
err = Pa_Initialize();
if (err != paNoError)
{
qInfo(logAudio()) << "ERROR: Cannot initialize Portaudio";
}
qInfo(logAudio()) << "PortAudio version: " << Pa_GetVersionInfo()->versionText;
int numDevices;
numDevices = Pa_GetDeviceCount();
qInfo(logAudio()) << "Pa_CountDevices returned" << numDevices;
const PaDeviceInfo* info;
for (int i = 0; i < numDevices; i++)
{
info = Pa_GetDeviceInfo(i);
if (info->maxInputChannels > 0) {
qInfo(logAudio()) << (i == Pa_GetDefaultInputDevice() ? "*" : " ") << "(" << i << ") Output Device : " << info->name;
ui->audioInputCombo->addItem(info->name, i);
}
if (info->maxOutputChannels > 0) {
qInfo(logAudio()) << (i == Pa_GetDefaultOutputDevice() ? "*" : " ") << "(" << i << ") Input Device : " << info->name;
ui->audioOutputCombo->addItem(info->name, i);
}
}
#else
// If no external library is configured, use QTMultimedia
@ -1466,6 +1500,7 @@ void wfmain::loadSettings()
#if defined(RTAUDIO)
rxSetup.port = ui->audioOutputCombo->itemData(audioOutputIndex).toInt();
#elif defined(PORTAUDIO)
rxSetup.port = ui->audioOutputCombo->itemData(audioOutputIndex).toInt();
#else
QVariant v = ui->audioOutputCombo->currentData();
rxSetup.port = v.value<QAudioDeviceInfo>();
@ -1482,6 +1517,7 @@ void wfmain::loadSettings()
#if defined(RTAUDIO)
txSetup.port = ui->audioInputCombo->itemData(audioInputIndex).toInt();
#elif defined(PORTAUDIO)
txSetup.port = ui->audioInputCombo->itemData(audioInputIndex).toInt();
#else
QVariant v = ui->audioInputCombo->currentData();
txSetup.port = v.value<QAudioDeviceInfo>();
@ -4223,6 +4259,7 @@ void wfmain::on_audioOutputCombo_currentIndexChanged(int value)
#if defined(RTAUDIO)
rxSetup.port = ui->audioOutputCombo->itemData(value).toInt();
#elif defined(PORTAUDIO)
rxSetup.port = ui->audioOutputCombo->itemData(value).toInt();
#else
QVariant v = ui->audioOutputCombo->itemData(value);
rxSetup.port = v.value<QAudioDeviceInfo>();
@ -4236,6 +4273,7 @@ void wfmain::on_audioInputCombo_currentIndexChanged(int value)
#if defined(RTAUDIO)
txSetup.port = ui->audioInputCombo->itemData(value).toInt();
#elif defined(PORTAUDIO)
txSetup.port = ui->audioInputCombo->itemData(value).toInt();
#else
QVariant v = ui->audioInputCombo->itemData(value);
txSetup.port = v.value<QAudioDeviceInfo>();

Wyświetl plik

@ -48,13 +48,29 @@ DEFINES += PREFIX=\\\"$$PREFIX\\\"
# DEFINES += RTAUDIO
# DEFINES += PORTAUDIO
# RTAudio defines
win32:DEFINES += __WINDOWS_WASAPI__
#win32:DEFINES += __WINDOWS_DS__ # Requires DirectSound libraries
linux:DEFINES += __LINUX_ALSA__
#linux:DEFINES += __LINUX_OSS__
#linux:DEFINES += __LINUX_PULSE__
macx:DEFINES += __MACOSX_CORE__
contains(DEFINES, RTAUDIO) {
# RTAudio defines
win32:DEFINES += __WINDOWS_WASAPI__
#win32:DEFINES += __WINDOWS_DS__ # Requires DirectSound libraries
linux:DEFINES += __LINUX_ALSA__
#linux:DEFINES += __LINUX_OSS__
#linux:DEFINES += __LINUX_PULSE__
macx:DEFINES += __MACOSX_CORE__
win32:SOURCES += ../rtaudio/RTAudio.cpp
win32:HEADERS += ../rtaudio/RTAUdio.h
!linux:INCLUDEPATH += ../rtaudio
linux:LIBS += -lpulse -lpulse-simple -lpthread
}
contains(DEFINES, PORTAUDIO) {
CONFIG(debug, release|debug) {
win32:LIBS += -L../portaudio/msvc/Win32/Debug/ -lportaudio_x86
} else {
win32:LIBS += -L../portaudio/msvc/Win32/Release/ -lportaudio_x86
}
win32:INCLUDEPATH += ../portaudio/include
!win32:LIBS += -lportaudio
}
macx:INCLUDEPATH += /usr/local/include /opt/local/include
macx:LIBS += -L/usr/local/lib -L/opt/local/lib
@ -111,12 +127,9 @@ CONFIG(debug, release|debug) {
win32:LIBS += -L../opus/win32/VS2015/Win32/Release/ -lopus
}
#linux:LIBS += -L./ -l$$QCPLIB -lpulse -lpulse-simple -lpthread
linux:LIBS += -L./ -l$$QCPLIB -lopus
macx:LIBS += -framework CoreAudio -framework CoreFoundation -lpthread -lopus
macx:LIBS += -framework CoreAudio -framework CoreFoundation -lpthread -lopus
#win32:SOURCES += rtaudio/RTAudio.cpp
#win32:HEADERS += rtaudio/RTAUdio.h
!linux:SOURCES += ../qcustomplot/qcustomplot.cpp
!linux:HEADERS += ../qcustomplot/qcustomplot.h
!linux:INCLUDEPATH += ../qcustomplot
@ -124,7 +137,6 @@ macx:LIBS += -framework CoreAudio -framework CoreFoundation -lpthread -lopus
!linux:INCLUDEPATH += ../opus/include
INCLUDEPATH += resampler
!linux:INCLUDEPATH += rtaudio
SOURCES += main.cpp\
wfmain.cpp \