From 384e41501251f747a58b421d37c4838514720d2b Mon Sep 17 00:00:00 2001 From: =?utf8?q?IOhannes=20m=20zm=C3=B6lnig=20=28Debian/GNU=29?= Date: Tue, 7 Dec 2021 10:44:06 +0100 Subject: [PATCH] New upstream version 1.4.2+ds0 --- CMakeLists.txt | 2 + jacktrip.pro | 6 +- macos/assemble_app.sh | 19 +- meson.build | 6 +- src/JackTrip.cpp | 3 +- src/JackTrip.h | 4 +- src/JackTripWorker.h | 4 +- src/Settings.cpp | 15 +- src/Settings.h | 2 +- src/UdpHubListener.h | 4 +- src/gui/messageDialog.cpp | 104 ++- src/gui/messageDialog.h | 32 +- src/gui/qjacktrip.cpp | 80 +- src/gui/qjacktrip.h | 15 +- src/gui/qjacktrip.ui | 437 ++++----- src/gui/qjacktrip_novs.ui | 1815 +++++++++++++++++++++++++++++++++++++ src/gui/textbuf.cpp | 68 ++ src/gui/textbuf.h | 61 ++ src/jacktrip_globals.h | 2 +- src/main.cpp | 65 +- subprojects/rtaudio.wrap | 9 +- 21 files changed, 2460 insertions(+), 293 deletions(-) create mode 100644 src/gui/qjacktrip_novs.ui create mode 100644 src/gui/textbuf.cpp create mode 100644 src/gui/textbuf.h diff --git a/CMakeLists.txt b/CMakeLists.txt index aaa2511..fbba160 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ project(QJackTrip) set(nogui FALSE) set(rtaudio TRUE) set(weakjack TRUE) +add_compile_definitions(NO_JTVS) add_compile_definitions(QT_OPENSOURCE) if (nogui) @@ -111,6 +112,7 @@ if (NOT nogui) src/gui/qjacktrip.cpp src/gui/about.cpp src/gui/messageDialog.cpp + src/gui/textbuf.cpp src/gui/qjacktrip.qrc ) diff --git a/jacktrip.pro b/jacktrip.pro index 3a86ce3..d8ef285 100644 --- a/jacktrip.pro +++ b/jacktrip.pro @@ -232,7 +232,8 @@ HEADERS += src/JackAudioInterface.h \ !nogui { HEADERS += src/gui/about.h \ src/gui/messageDialog.h \ - src/gui/qjacktrip.h + src/gui/qjacktrip.h \ + src/gui/textbuf.h } rtaudio|bundled_rtaudio { @@ -270,7 +271,8 @@ SOURCES += src/JackAudioInterface.cpp \ !nogui { SOURCES += src/gui/messageDialog.cpp \ src/gui/qjacktrip.cpp \ - src/gui/about.cpp + src/gui/about.cpp \ + src/gui/textbuf.cpp } !nogui { diff --git a/macos/assemble_app.sh b/macos/assemble_app.sh index 1d89e3f..d52a3f8 100755 --- a/macos/assemble_app.sh +++ b/macos/assemble_app.sh @@ -13,7 +13,7 @@ BINARY="../builddir/jacktrip" OPTIND=1 -while getopts ":ic:u:p:a:b:" opt; do +while getopts ":ihc:u:p:a:b:" opt; do case $opt in i) BUILD_INSTALLER=true @@ -36,6 +36,23 @@ while getopts ":ic:u:p:a:b:" opt; do \?) echo "Invalid option -$OPTARG ignored." ;; + h) + echo "JackTrip App Bundle assembly script." + echo "Copyright (C) 2020-2021 Aaron Wyatt et al." + echo "Relased under the GNU GPLv3 License." + echo "" + echo "Usage: ./assemble-app.sh [options]" + echo "" + echo "Options:" + echo " -b The binary file to be placed in the app bundle. (Defaults to ../builddir/jacktrip)" + echo " -i Build an installer package as well. (Requires Packages to be installed.)" + echo " -c Name of the developer certificate to use for signing (No signing by default.)" + echo " -u Apple ID username (email address) for installer notarization." + echo " -p App specific password for installer notarization." + echo " -a ASC provider for notarization. (Only required if you belong to multiple dev teams.)" + echo " -h Display this help screen and exit." + exit 0 + ;; :) echo "Option $OPTARG requires an argument." exit 1 diff --git a/meson.build b/meson.build index 565d376..258661b 100644 --- a/meson.build +++ b/meson.build @@ -90,13 +90,15 @@ else qt5_dep = dependency('qt5', modules: ['Core', 'Gui', 'Network', 'Widgets'], include_type: 'system') src += ['src/gui/qjacktrip.cpp', 'src/gui/about.cpp', - 'src/gui/messageDialog.cpp'] + 'src/gui/messageDialog.cpp', + 'src/gui/textbuf.cpp'] ui_h += ['src/gui/qjacktrip.ui', 'src/gui/messageDialog.ui', 'src/gui/about.ui'] moc_h += ['src/gui/about.h', 'src/gui/qjacktrip.h', - 'src/gui/messageDialog.h'] + 'src/gui/messageDialog.h', + 'src/gui/textbuf.h'] qres = ['src/gui/qjacktrip.qrc'] endif deps += qt5_dep diff --git a/src/JackTrip.cpp b/src/JackTrip.cpp index c489e6f..e3733d5 100644 --- a/src/JackTrip.cpp +++ b/src/JackTrip.cpp @@ -582,8 +582,7 @@ void JackTrip::completeConnection() if (mIOStatTimeout > 0) { cout << "STATS" << mIOStatTimeout << endl; if (!mIOStatStream.isNull()) { - mIOStatLogStream.rdbuf( - (reinterpret_cast(mIOStatStream.data()))->rdbuf()); + mIOStatLogStream.rdbuf((mIOStatStream.data()->rdbuf())); } QTimer* timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(onStatTimer())); diff --git a/src/JackTrip.h b/src/JackTrip.h index 5d3dde7..f7fa1f6 100644 --- a/src/JackTrip.h +++ b/src/JackTrip.h @@ -271,7 +271,7 @@ class JackTrip : public QObject virtual void setNumOutputChannels(int num_chans) { mNumAudioChansOut = num_chans; } virtual void setIOStatTimeout(int timeout) { mIOStatTimeout = timeout; } - virtual void setIOStatStream(QSharedPointer statStream) + virtual void setIOStatStream(QSharedPointer statStream) { mIOStatStream = statStream; } @@ -678,7 +678,7 @@ class JackTrip : public QObject volatile bool mHasShutdown; bool mConnectDefaultAudioPorts; ///< Connect or not default audio ports - QSharedPointer mIOStatStream; + QSharedPointer mIOStatStream; int mIOStatTimeout; std::ostream mIOStatLogStream; double mSimulatedLossRate; diff --git a/src/JackTripWorker.h b/src/JackTripWorker.h index bc6665f..e05dbdc 100644 --- a/src/JackTripWorker.h +++ b/src/JackTripWorker.h @@ -113,7 +113,7 @@ class JackTripWorker : public QObject void setUseRtUdpPriority(bool use) { mUseRtUdpPriority = use; } void setIOStatTimeout(int timeout) { mIOStatTimeout = timeout; } - void setIOStatStream(QSharedPointer statStream) + void setIOStatStream(QSharedPointer statStream) { mIOStatStream = statStream; } @@ -181,7 +181,7 @@ class JackTripWorker : public QObject bool mUseRtUdpPriority = false; int mIOStatTimeout = 0; - QSharedPointer mIOStatStream; + QSharedPointer mIOStatStream; #ifdef WAIR // wair int mNumNetRevChans = 0; ///< Number of Net Channels = net combs bool mWAIR = false; diff --git a/src/Settings.cpp b/src/Settings.cpp index 84299b8..d8aa4d9 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -461,12 +461,15 @@ void Settings::parseInput(int argc, char** argv) break; case 'G': // IO Stat log file //------------------------------------------------------- - mIOStatStream.reset(new std::ofstream(optarg)); - if (!mIOStatStream->is_open()) { - printUsage(); - std::cerr << "--iostatlog FAILED to open " << optarg << " for writing." - << endl; - std::exit(1); + { + std::ofstream *outStream = new std::ofstream(optarg); + if (!outStream->is_open()) { + printUsage(); + std::cerr << "--iostatlog FAILED to open " << optarg << " for writing." + << endl; + std::exit(1); + } + mIOStatStream.reset(outStream); } break; case OPT_BUFSTRATEGY: // Buf strategy diff --git a/src/Settings.h b/src/Settings.h index 2dd12b3..569ca27 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -125,7 +125,7 @@ class Settings : public QObject unsigned int mHubConnectionMode = JackTrip::SERVERTOCLIENT; bool mConnectDefaultAudioPorts = true; ///< Connect or not jack audio ports int mIOStatTimeout = 0; - QSharedPointer mIOStatStream; + QSharedPointer mIOStatStream; Effects mEffects = false; // outgoing limiter OFF by default double mSimulatedLossRate = 0.0; double mSimulatedJitterRate = 0.0; diff --git a/src/UdpHubListener.h b/src/UdpHubListener.h index e0208fa..07554a8 100644 --- a/src/UdpHubListener.h +++ b/src/UdpHubListener.h @@ -186,7 +186,7 @@ class UdpHubListener : public QObject #endif int mIOStatTimeout; - QSharedPointer mIOStatStream; + QSharedPointer mIOStatStream; int mBufferStrategy; int mBroadcastQueue; @@ -240,7 +240,7 @@ class UdpHubListener : public QObject } void setIOStatTimeout(int timeout) { mIOStatTimeout = timeout; } - void setIOStatStream(QSharedPointer statStream) + void setIOStatStream(QSharedPointer statStream) { mIOStatStream = statStream; } diff --git a/src/gui/messageDialog.cpp b/src/gui/messageDialog.cpp index 35c70a7..f4f046b 100644 --- a/src/gui/messageDialog.cpp +++ b/src/gui/messageDialog.cpp @@ -26,32 +26,108 @@ #include "messageDialog.h" #include "ui_messageDialog.h" +#include +#include +#include +#include -MessageDialog::MessageDialog(QWidget* parent) - : QDialog(parent), m_ui(new Ui::MessageDialog), m_ioTimer(new QTimer(this)) +MessageDialog::MessageDialog(QWidget* parent, QString windowFunction, quint32 streamCount) + : QDialog(parent) + , m_ui(new Ui::MessageDialog) + , m_outStreams(streamCount) + , m_outBufs(streamCount) + , m_windowFunction(windowFunction) { m_ui->setupUi(this); - connect(&m_ioTimer, &QTimer::timeout, this, &MessageDialog::writeOutput); - m_ioTimer.setInterval(1000); + for (quint32 i = 0; i < streamCount; i++) { + m_outBufs[i].reset(new textbuf); + m_outStreams[i].reset(new std::ostream(m_outBufs.at(i).data())); + connect(m_outBufs.at(i).data(), &textbuf::outputString, this, &MessageDialog::receiveOutput, Qt::QueuedConnection); + } + + m_ui->messagesTextEdit->setContextMenuPolicy(Qt::CustomContextMenu); + connect(m_ui->messagesTextEdit, &QPlainTextEdit::customContextMenuRequested, this, &MessageDialog::provideContextMenu); + m_ui->messagesTextEdit->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); + connect(this, &QDialog::rejected, this, &MessageDialog::savePosition); + + if (!m_windowFunction.isEmpty()) { + setWindowTitle(m_windowFunction); + } +} + +void MessageDialog::showEvent(QShowEvent* event) +{ + QDialog::showEvent(event); + if (!m_windowFunction.isEmpty()) { + QSettings settings; + settings.beginGroup("Window"); + QByteArray geometry = settings.value(m_windowFunction + "Geometry").toByteArray(); + if (geometry.size() > 0) { + restoreGeometry(geometry); + } + } +} + +void MessageDialog::closeEvent(QCloseEvent* event) +{ + QDialog::closeEvent(event); + savePosition(); +} + +QSharedPointer MessageDialog::getOutputStream(int index) +{ + if (index >=0 && index < m_outStreams.size()) { + return m_outStreams.at(index); + } + return QSharedPointer(); +} + +bool MessageDialog::setRelayStream(std::ostream *relay, int index) +{ + if (index >=0 && index < m_outBufs.size()) { + m_outBufs.at(index)->setOutStream(relay); + } + return false; } -void MessageDialog::setStatsFile(QSharedPointer statsFile) +void MessageDialog::clearOutput() { m_ui->messagesTextEdit->clear(); - m_ioStatsFile = statsFile; } -void MessageDialog::startMonitoring() { m_ioTimer.start(); } +void MessageDialog::receiveOutput(const QString& output) +{ + // Automatically scroll if we're at the bottom of the text box. + bool autoScroll = (m_ui->messagesTextEdit->verticalScrollBar()->value() == m_ui->messagesTextEdit->verticalScrollBar()->maximum()); + // Make sure our cursor is at the end. + m_ui->messagesTextEdit->moveCursor(QTextCursor::End); + m_ui->messagesTextEdit->insertPlainText(output); + if (autoScroll) { + m_ui->messagesTextEdit->verticalScrollBar()->setValue(m_ui->messagesTextEdit->verticalScrollBar()->maximum()); + } +} -void MessageDialog::stopMonitoring() { m_ioTimer.stop(); } +void MessageDialog::provideContextMenu() +{ + // Add a custom context menu entry to clear the output. + QMenu *menu = m_ui->messagesTextEdit->createStandardContextMenu(); + QAction *action = menu->addAction(QIcon::fromTheme("edit-delete"), "Clear"); + connect(action, &QAction::triggered, this, &MessageDialog::clearOutput); + menu->exec(QCursor::pos()); +} -void MessageDialog::writeOutput() +void MessageDialog::savePosition() { - while (!m_ioStatsFile->atEnd()) { - m_ui->messagesTextEdit->moveCursor(QTextCursor::End); - m_ui->messagesTextEdit->insertPlainText(m_ioStatsFile->readLine()); - (m_ioStatsFile->readLine()); + if (!m_windowFunction.isEmpty()) { + QSettings settings; + settings.beginGroup("Window"); + settings.setValue(m_windowFunction + "Geometry", saveGeometry()); + settings.endGroup(); } } -MessageDialog::~MessageDialog() = default; +MessageDialog::~MessageDialog() { + if (isVisible()) { + savePosition(); + } +} diff --git a/src/gui/messageDialog.h b/src/gui/messageDialog.h index ccb0bcd..579d91c 100644 --- a/src/gui/messageDialog.h +++ b/src/gui/messageDialog.h @@ -28,8 +28,9 @@ #include #include -#include -#include +#include +#include +#include "textbuf.h" namespace Ui { @@ -41,21 +42,28 @@ class MessageDialog : public QDialog Q_OBJECT public: - explicit MessageDialog(QWidget* parent = nullptr); + explicit MessageDialog(QWidget* parent = nullptr, QString windowFunction = "", quint32 streamCount = 1); ~MessageDialog() override; - - void setStatsFile(QSharedPointer statsFile); - void startMonitoring(); - void stopMonitoring(); - + + void showEvent(QShowEvent* event) override; + void closeEvent(QCloseEvent* event) override; + + QSharedPointer getOutputStream(int index = 0); + bool setRelayStream(std::ostream *relay, int index = 0); + + public slots: + void clearOutput(); + private slots: - void writeOutput(); + void receiveOutput(const QString& output); + void provideContextMenu(); + void savePosition(); private: QScopedPointer m_ui; - QSharedPointer m_ioStatsFile; - // Using a QFileSystem watcher didn't work on OS X, so use a timer instead. - QTimer m_ioTimer; + QVector> m_outStreams; + QVector> m_outBufs; + QString m_windowFunction; }; #endif // MESSAGEDIALOG_H diff --git a/src/gui/qjacktrip.cpp b/src/gui/qjacktrip.cpp index 1ed8793..0ccb5a3 100644 --- a/src/gui/qjacktrip.cpp +++ b/src/gui/qjacktrip.cpp @@ -34,7 +34,11 @@ #include #include "about.h" +#ifdef NO_JTVS +#include "ui_qjacktrip_novs.h" +#else #include "ui_qjacktrip.h" +#endif #ifdef USE_WEAK_JACK #include "weak_libjack.h" #endif @@ -50,9 +54,16 @@ QJackTrip::QJackTrip(QWidget* parent) : QMainWindow(parent) +#ifdef NO_JTVS , m_ui(new Ui::QJackTrip) +#else + , m_ui(new Ui::QJackTripVS) +#endif , m_netManager(new QNetworkAccessManager(this)) - , m_messageDialog(new MessageDialog(this)) + , m_statsDialog(new MessageDialog(this, "Stats")) + , m_debugDialog(new MessageDialog(this, "Debug", 2)) + , m_realCout(std::cout.rdbuf()) + , m_realCerr(std::cerr.rdbuf()) , m_jackTripRunning(false) , m_isExiting(false) , m_hasIPv4Reply(false) @@ -64,6 +75,12 @@ QJackTrip::QJackTrip(QWidget* parent) QCoreApplication::setOrganizationName("jacktrip"); QCoreApplication::setOrganizationDomain("jacktrip.org"); QCoreApplication::setApplicationName("JackTrip"); + + // Set up our debug window, and relay everything to our real cout. + std::cout.rdbuf(m_debugDialog->getOutputStream()->rdbuf()); + std::cerr.rdbuf(m_debugDialog->getOutputStream(1)->rdbuf()); + m_debugDialog->setRelayStream(&m_realCout); + m_debugDialog->setRelayStream(&m_realCerr, 1); // Create all our UI connections. connect(m_ui->typeComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, @@ -113,6 +130,16 @@ QJackTrip::QJackTrip(QWidget* parent) connect(m_ui->ioStatsCheckBox, &QCheckBox::stateChanged, this, [=]() { m_ui->ioStatsLabel->setEnabled(m_ui->ioStatsCheckBox->isChecked()); m_ui->ioStatsSpinBox->setEnabled(m_ui->ioStatsCheckBox->isChecked()); + if (!m_ui->ioStatsCheckBox->isChecked()) { + m_statsDialog->hide(); + } + }); + connect(m_ui->verboseCheckBox, &QCheckBox::stateChanged, this, [=]() { + gVerboseFlag = m_ui->verboseCheckBox->isChecked(); + if (!gVerboseFlag) { + m_debugDialog->hide(); + m_debugDialog->clearOutput(); + } }); connect(m_ui->jitterCheckBox, &QCheckBox::stateChanged, this, [=]() { m_ui->broadcastCheckBox->setEnabled(m_ui->jitterCheckBox->isChecked()); @@ -195,12 +222,9 @@ QJackTrip::QJackTrip(QWidget* parent) // Set up our interface for the default Client run mode. //(loadSettings will take care of the UI in all other cases.) - m_ui->remoteNameLabel->setVisible(false); - m_ui->remoteNameEdit->setVisible(false); m_ui->basePortLabel->setVisible(false); m_ui->basePortSpinBox->setVisible(false); m_ui->requireAuthGroupBox->setVisible(false); - m_ui->authGroupBox->setVisible(false); #ifdef __RT_AUDIO__ connect(m_ui->backendComboBox, QOverload::of(&QComboBox::currentIndexChanged), @@ -351,11 +375,11 @@ void QJackTrip::showEvent(QShowEvent* event) // One of our arguments will always be --gui, so if that's the only one // then we don't need to show the warning message. - if (m_argc > 2) { + if ((!gVerboseFlag && m_argc > 2) || m_argc > 3) { QMessageBox msgBox; msgBox.setText( "The GUI version of JackTrip currently\nignores any command line " - "options.\n\nThis may change in future."); + "options other\nthan the verbose option (-V).\n\nThis may change in future."); msgBox.setWindowTitle("Command line options"); msgBox.exec(); } @@ -373,7 +397,6 @@ void QJackTrip::processFinished() #ifdef __MAC_OSX__ m_noNap.enableNap(); #endif - if (m_ui->ioStatsCheckBox->isChecked()) { m_messageDialog->stopMonitoring(); } m_ui->disconnectButton->setEnabled(false); if (m_ui->typeComboBox->currentIndex() == HUB_SERVER) { m_udpHub.reset(); @@ -620,6 +643,10 @@ void QJackTrip::start() m_ui->connectButton->setEnabled(false); enableUi(false); m_jackTripRunning = true; + + if (gVerboseFlag) { + m_debugDialog->show(); + } // Start the appropriate JackTrip process. try { @@ -667,10 +694,10 @@ void QJackTrip::start() // Open our stats window if needed if (m_ui->ioStatsCheckBox->isChecked()) { - setupStatsWindow(); + m_statsDialog->clearOutput(); + m_statsDialog->show(); m_udpHub->setIOStatTimeout(m_ui->ioStatsSpinBox->value()); - m_udpHub->setIOStatStream(QSharedPointer( - new std::ofstream(m_ioStatsOutput->fileName().toUtf8().constData()))); + m_udpHub->setIOStatStream(m_statsDialog->getOutputStream()); } QObject::connect(m_udpHub.data(), &UdpHubListener::signalStopped, this, @@ -785,10 +812,10 @@ void QJackTrip::start() // Open our stats window if needed if (m_ui->ioStatsCheckBox->isChecked()) { - setupStatsWindow(); + m_statsDialog->clearOutput(); + m_statsDialog->show(); m_jackTrip->setIOStatTimeout(m_ui->ioStatsSpinBox->value()); - m_jackTrip->setIOStatStream(QSharedPointer( - new std::ofstream(m_ioStatsOutput->fileName().toUtf8().constData()))); + m_jackTrip->setIOStatStream(m_statsDialog->getOutputStream()); } // Append any plugins @@ -964,6 +991,8 @@ void QJackTrip::loadSettings() m_ui->resolutionComboBox->setCurrentIndex(settings.value("Resolution", 1).toInt()); m_ui->connectAudioCheckBox->setChecked(settings.value("ConnectAudio", true).toBool()); m_ui->realTimeCheckBox->setChecked(settings.value("RTNetworking", true).toBool()); + // This may have been set by the command line, so don't overwrite if that's the case. + m_ui->verboseCheckBox->setChecked(gVerboseFlag || settings.value("Debug", 0).toBool()); m_lastPath = settings.value("LastPath", QDir::homePath()).toString(); settings.beginGroup("RecentServers"); @@ -1055,7 +1084,7 @@ void QJackTrip::loadSettings() settings.beginGroup("Window"); QByteArray geometry = settings.value("Geometry").toByteArray(); if (geometry.size() > 0) { - restoreGeometry(settings.value("Geometry").toByteArray()); + restoreGeometry(geometry); } else { // Because of hidden elements in our dialog window, it's vertical size in the // creator is getting rediculous. Set it to something sensible by default if this @@ -1085,6 +1114,7 @@ void QJackTrip::saveSettings() settings.setValue("Resolution", m_ui->resolutionComboBox->currentIndex()); settings.setValue("ConnectAudio", m_ui->connectAudioCheckBox->isChecked()); settings.setValue("RTNetworking", m_ui->realTimeCheckBox->isChecked()); + settings.setValue("Debug", m_ui->verboseCheckBox->isChecked()); settings.setValue("LastPath", m_lastPath); settings.beginGroup("RecentServers"); @@ -1151,15 +1181,6 @@ void QJackTrip::saveSettings() settings.endGroup(); } -void QJackTrip::setupStatsWindow() -{ - m_ioStatsOutput.reset(new QTemporaryFile()); - m_ioStatsOutput->open(); - m_messageDialog->setStatsFile(m_ioStatsOutput); - m_messageDialog->show(); - m_messageDialog->startMonitoring(); -} - void QJackTrip::appendPlugins(JackTrip* jackTrip, int numSendChannels, int numRecvChannels) { @@ -1286,7 +1307,7 @@ QString QJackTrip::commandLineFromCurrentOptions() // Auth settings if (m_ui->typeComboBox->currentIndex() == HUB_SERVER) { if (m_ui->requireAuthCheckBox->isChecked()) { - commandLine.append(QString(" -A")); + commandLine.append(" -A"); if (!m_ui->certEdit->text().isEmpty()) { commandLine.append(" --certfile ").append(m_ui->certEdit->text()); } @@ -1299,7 +1320,7 @@ QString QJackTrip::commandLineFromCurrentOptions() } } else if (m_ui->typeComboBox->currentIndex() == HUB_CLIENT) { if (m_ui->authCheckBox->isChecked()) { - commandLine.append(QString(" -A")); + commandLine.append(" -A"); if (!m_ui->usernameEdit->text().isEmpty()) { commandLine.append(" --username ").append(m_ui->usernameEdit->text()); } @@ -1382,6 +1403,8 @@ QString QJackTrip::commandLineFromCurrentOptions() if (m_ui->ioStatsCheckBox->isChecked()) { commandLine.append(QString(" -I %1").arg(m_ui->ioStatsSpinBox->value())); } + + if (m_ui->verboseCheckBox->isChecked()) { commandLine.append(" -V"); } if (m_ui->realTimeCheckBox->isChecked()) { commandLine.append(" --udprt"); } @@ -1446,4 +1469,9 @@ void QJackTrip::showCommandLineMessageBox() msgBox.exec(); } -QJackTrip::~QJackTrip() = default; +QJackTrip::~QJackTrip() +{ + //Restore cout. (Stops a crash on exit.) + std::cout.rdbuf(m_realCout.rdbuf()); + std::cerr.rdbuf(m_realCerr.rdbuf()); +} diff --git a/src/gui/qjacktrip.h b/src/gui/qjacktrip.h index 6d57080..1246963 100644 --- a/src/gui/qjacktrip.h +++ b/src/gui/qjacktrip.h @@ -51,7 +51,11 @@ namespace Ui { +#ifdef NO_JTVS class QJackTrip; +#else +class QJackTripVS; +#endif } class QJackTrip : public QMainWindow @@ -102,18 +106,23 @@ class QJackTrip : public QMainWindow void populateDeviceMenu(QComboBox* menu, bool isInput); #endif - void setupStatsWindow(); void appendPlugins(JackTrip* jackTrip, int numSendChannels, int numRecvChannels); QString commandLineFromCurrentOptions(); void showCommandLineMessageBox(); +#ifdef NO_JTVS QScopedPointer m_ui; +#else + QScopedPointer m_ui; +#endif QScopedPointer m_udpHub; QScopedPointer m_jackTrip; QScopedPointer m_netManager; - QScopedPointer m_messageDialog; - QSharedPointer m_ioStatsOutput; + QScopedPointer m_statsDialog; + QScopedPointer m_debugDialog; + std::ostream m_realCout; + std::ostream m_realCerr; bool m_jackTripRunning; bool m_isExiting; diff --git a/src/gui/qjacktrip.ui b/src/gui/qjacktrip.ui index 5387103..3529a1a 100644 --- a/src/gui/qjacktrip.ui +++ b/src/gui/qjacktrip.ui @@ -1,13 +1,13 @@ - QJackTrip - + QJackTripVS + 0 0 409 - 817 + 845 @@ -25,6 +25,9 @@ To connect to a p2p (peer to peer) server you need to run as a p2p client. To connect to a hub server you need to run as a hub client. + + 2 + P2P Client @@ -491,8 +494,8 @@ To connect to a hub server you need to run as a hub client. Advanced options - - + + 0 @@ -500,10 +503,50 @@ To connect to a hub server you need to run as a hub client. - &Local Port + Audio &Bit Resolution - localPortSpinBox + resolutionComboBox + + + + + + + Select the audio bit resolution. + + + 1 + + + + 8 + + + + + 16 + + + + + 24 + + + + + 32 + + + + + + + + Set the name of the Jack client as it will appear on the hub server. + + + 64 @@ -523,7 +566,56 @@ To connect to a hub server you need to run as a hub client. - + + + + + 0 + 0 + + + + Remote Client &Name + + + remoteNameEdit + + + + + + + + 0 + 0 + + + + Remote &Port + + + remotePortSpinBox + + + + + + + Set the local port to use for the connection. The default is 4464. +(Useful for running multiple hub clients behind the same router.) + + + 1024 + + + 65535 + + + 4464 + + + + true @@ -597,8 +689,8 @@ To connect to a hub server you need to run as a hub client. - - + + 0 @@ -606,61 +698,15 @@ To connect to a hub server you need to run as a hub client. - Remote Client &Name + &Local Port - remoteNameEdit - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Connect the Jack client to the default system audio ports. - - - &Connect default audio ports - - - true - - - - - - - Set the local port to use for the connection. The default is 4464. -(Useful for running multiple hub clients behind the same router.) - - - 1024 - - - 65535 - - - 4464 + localPortSpinBox - - - - false - + + 0 @@ -668,15 +714,28 @@ To connect to a hub server you need to run as a hub client. - Reporting &Interval (s) + &Queue Buffer Length - ioStatsSpinBox + queueLengthSpinBox - - + + + + Qt::Vertical + + + + 20 + 40 + + + + + + 0 @@ -684,15 +743,15 @@ To connect to a hub server you need to run as a hub client. - Remote &Port + &UDP Base Port - remotePortSpinBox + basePortSpinBox - - + + 0 @@ -700,28 +759,18 @@ To connect to a hub server you need to run as a hub client. - Audio &Bit Resolution + Custom Client &Name - resolutionComboBox + clientNameEdit - - - - Set the name of the Jack client. - - - 64 - - - JackTrip + + + + false - - - - 0 @@ -729,41 +778,41 @@ To connect to a hub server you need to run as a hub client. - &Redundancy + Reporting &Interval (s) - redundancySpinBox + ioStatsSpinBox - - - - - 0 - 0 - + + + + Set the queue buffer length, in packet size. - - &Queue Buffer Length + + 2 - - queueLengthSpinBox + + 4 - - + + - Set the name of the Jack client as it will appear on the hub server. + Number of redundant packets to be sent to avoid glitches related to packet loss. - - 64 + + 1 + + + 1 - - + + 0 @@ -771,10 +820,10 @@ To connect to a hub server you need to run as a hub client. - Custom Client &Name + &Redundancy - clientNameEdit + redundancySpinBox @@ -794,66 +843,53 @@ To connect to a hub server you need to run as a hub client. - - + + - Select the audio bit resolution. + Set the remote port to use for the connection. The default is 4464. - - 1 + + 1024 + + + 65535 + + + 4464 - - - 8 - - - - - 16 - - - - - 24 - - - - - 32 - - - - + + - Number of redundant packets to be sent to avoid glitches related to packet loss. + Connect the Jack client to the default system audio ports. - - 1 + + &Connect default audio ports - - 1 + + true - - + + - Set the queue buffer length, in packet size. + Set the name of the Jack client. - - 2 + + 64 - - 4 + + JackTrip - - + + - Set the remote port to use for the connection. The default is 4464. + Set the base UDP port to be used by connecting hub clients. The default is 61002. +(You should manually set this if running multiple hub servers on the same machine.) 1024 @@ -862,11 +898,11 @@ To connect to a hub server you need to run as a hub client. 65535 - 4464 + 61002 - + @@ -900,39 +936,6 @@ To connect to a hub server you need to run as a hub client. - - - - - 0 - 0 - - - - &UDP Base Port - - - basePortSpinBox - - - - - - - Set the base UDP port to be used by connecting hub clients. The default is 61002. -(You should manually set this if running multiple hub servers on the same machine.) - - - 1024 - - - 65535 - - - 61002 - - - @@ -946,6 +949,13 @@ To connect to a hub server you need to run as a hub client. + + + + Show &Debug Information + + + @@ -1189,28 +1199,28 @@ To connect to a hub server you need to run as a hub client. - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - &Refresh Device List - - - - + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + &Refresh Device List + + + + @@ -1222,7 +1232,7 @@ To connect to a hub server you need to run as a hub client. - false + true Packets @@ -1237,12 +1247,15 @@ To connect to a hub server you need to run as a hub client. Automatically set the &queue length + + true + - false + true @@ -1271,7 +1284,7 @@ To connect to a hub server you need to run as a hub client. - false + true @@ -1317,7 +1330,7 @@ for better quality at the expense of latency. - false + true This will override the queue buffer length entered in the advanced options tab. (The default value is 500.) @@ -1750,9 +1763,6 @@ and wetness is the essence of beauty. keyBrowse credsEdit credsBrowse - authCheckBox - usernameEdit - passwordEdit aboutButton clientNameEdit remoteNameEdit @@ -1766,6 +1776,9 @@ and wetness is the essence of beauty. realTimeCheckBox ioStatsCheckBox ioStatsSpinBox + authCheckBox + usernameEdit + passwordEdit commandLineButton useDefaultsButton backendComboBox diff --git a/src/gui/qjacktrip_novs.ui b/src/gui/qjacktrip_novs.ui new file mode 100644 index 0000000..9d67bd1 --- /dev/null +++ b/src/gui/qjacktrip_novs.ui @@ -0,0 +1,1815 @@ + + + QJackTrip + + + + 0 + 0 + 409 + 817 + + + + JackTrip + + + + :/qjacktrip/icon.png:/qjacktrip/icon.png + + + + + + + To connect to a p2p (peer to peer) server you need to run as a p2p client. +To connect to a hub server you need to run as a hub client. + + + 2 + + + + P2P Client + + + + + P2P Server + + + + + Hub Client + + + + + Hub Server + + + + + + + + + + false + + + Connect + + + + + + + false + + + Disconnect + + + + + + + Exit + + + + + + + + + If running as a server, this is the address you should supply to the other clients. +(You will need to enable any port forwarding on your router manually.) + + + Looking up external IP address... + + + + + + + + 0 + 0 + + + + Enter the IP address or the hostname of the server you want to connect to. + + + true + + + 5 + + + QComboBox::NoInsert + + + + + + + true + + + &Address of server + + + addressComboBox + + + + + + + &Run JackTrip as + + + typeComboBox + + + + + + + true + + + + 391 + 0 + + + + 0 + + + false + + + false + + + + true + + + Basic options + + + + + + + + + + 0 + 0 + + + + &Received from network: + + + channelRecvSpinBox + + + + + + + + 0 + 0 + + + + Number of audio channels toaccept from the network. + + + 1 + + + 2 + + + + + + + Number of audio channels to send to the network. + + + 1 + + + 2 + + + + + + + &Sent to network: + + + channelSendSpinBox + + + + + + + + 0 + 0 + + + + &Number of channels + + + channelRecvSpinBox + + + + + + + + + + true + + + + + + + + + Supply a username and password to connect to the server. + + + &Use Authentication + + + + + + + false + + + Enter your password. (This will not be shown or saved.) + + + QLineEdit::Password + + + 0 + + + + + + + false + + + Enter your username for the server. + + + + + + + false + + + &Password + + + passwordEdit + + + + + + + false + + + &Username + + + usernameEdit + + + + + + + + + + Select how you want audio to be routed by the hub server. + + + 0 + + + + Server to clients + + + + + Client loopback + + + + + Client fan out/in but no loopback + + + + + Full Mix + + + + + No auto patching + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + About + + + + + + + + + + + + + + + false + + + Browse + + + + + + + (This is a work in progress and needs to be manually configured outside of the app. Only use if you know what you're doing.) + + + true + + + + + + + false + + + &Certificate File + + + certEdit + + + + + + + false + + + &Key File + + + keyEdit + + + + + + + false + + + Choose the private key that the server should use for the SSL connection. + + + + + + + false + + + Choose the certificate file that the server should use to establish an initial SSL connection. + + + + + + + false + + + Browse + + + + + + + Require clients to connect with a username and password. + + + &Require Authentication + + + + + + + false + + + &Credentials File + + + credsEdit + + + + + + + false + + + Choose the file containing the list of usernames and passwords. + + + + + + + false + + + Browse + + + + + + + + + + Stop JackTrip if no network traffic has been received for 10 seconds. + + + &Disconnect after 10 seconds of no network activity + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + Silence the audio when there's a buffer underrun. + + + Set buffer to &zero when underrun occurs + + + + + + + + 0 + 0 + + + + Hub auto&patch mode + + + autoPatchComboBox + + + + + + + + true + + + Advanced options + + + + + + + 0 + 0 + + + + &Queue Buffer Length + + + queueLengthSpinBox + + + + + + + Set the name of the Jack client. + + + 64 + + + JackTrip + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + Audio &Bit Resolution + + + resolutionComboBox + + + + + + + Set the name of the Jack client as it will appear on the hub server. + + + 64 + + + + + + + Select the audio bit resolution. + + + 1 + + + + 8 + + + + + 16 + + + + + 24 + + + + + 32 + + + + + + + + Use real time priority for the networking threads. + + + Enable real&time priority for networking threads + + + true + + + + + + + false + + + Choose how often stats should be reported. + + + 1 + + + 120 + + + + + + + Set the base UDP port to be used by connecting hub clients. The default is 61002. +(You should manually set this if running multiple hub servers on the same machine.) + + + 1024 + + + 65535 + + + 61002 + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Show the equivalent command line for the current settings. + + + Get Command &Line + + + + + + + Use &Defaults + + + + + + + + + + 0 + 0 + + + + Remote Client &Name + + + remoteNameEdit + + + + + + + + 0 + 0 + + + + Display IO stats in another window. + + + Display &IO Stats + + + + + + + + 0 + 0 + + + + Remote &Port + + + remotePortSpinBox + + + + + + + + 0 + 0 + + + + Custom Client &Name + + + clientNameEdit + + + + + + + + 0 + 0 + + + + &Redundancy + + + redundancySpinBox + + + + + + + Connect the Jack client to the default system audio ports. + + + &Connect default audio ports + + + true + + + + + + + Set the local port to use for the connection. The default is 4464. +(Useful for running multiple hub clients behind the same router.) + + + 1024 + + + 65535 + + + 4464 + + + + + + + Set the remote port to use for the connection. The default is 4464. + + + 1024 + + + 65535 + + + 4464 + + + + + + + + 0 + 0 + + + + &UDP Base Port + + + basePortSpinBox + + + + + + + + 0 + 0 + + + + &Local Port + + + localPortSpinBox + + + + + + + Number of redundant packets to be sent to avoid glitches related to packet loss. + + + 1 + + + 1 + + + + + + + false + + + + 0 + 0 + + + + Reporting &Interval (s) + + + ioStatsSpinBox + + + + + + + Set the queue buffer length, in packet size. + + + 2 + + + 4 + + + + + + + Show &Debug Information + + + + + + + + Audio Backend + + + + + + + 0 + 0 + + + + Audio &Backend: + + + backendComboBox + + + + + + + <html><head/><body><p>Choose the audio backend to use. JACK is the default and is well tested, but requires the JACK audio server to be installed.</p><p>RtAudio is still a work in progress, but it works with your operating system's native audio drivers and requires no additional software.</p></body></html> + + + + JACK + + + + + RtAudio + + + + + + + + false + + + + 0 + 0 + + + + &Sampling Rate: + + + sampleRateComboBox + + + + + + + false + + + <html><head/><body><p>Set the audio sample rate to use with the RtAudio backend. This setting should be the same on both ends of the connection.</p></body></html> + + + 48000 + + + 3 + + + + 22050 + + + + + 32000 + + + + + 44100 + + + + + 48000 + + + + + 88200 + + + + + 96000 + + + + + 192000 + + + + + + + + false + + + + 0 + 0 + + + + &Buffer Size: + + + bufferSizeComboBox + + + + + + + false + + + <html><head/><body><p>Set the driver's buffer size to use with the RtAudio backend.</p></body></html> + + + 3 + + + + 16 + + + + + 32 + + + + + 64 + + + + + 128 + + + + + 256 + + + + + 512 + + + + + 1024 + + + + + + + + false + + + + 0 + 0 + + + + &Input Device: + + + inputDeviceComboBox + + + + + + + false + + + + + + + false + + + + 0 + 0 + + + + &Output Device: + + + outputDeviceComboBox + + + + + + + false + + + + + + + Qt::Vertical + + + + 20 + 444 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + &Refresh Device List + + + + + + + + + + Jitter Buffer + + + + + + true + + + Packets + + + + + + + true + + + Automatically set the &queue length + + + true + + + + + + + true + + + + 0 + 0 + + + + Aim to &drop no more than one in every + + + autoQueueSpinBox + + + + + + + false + + + Qt::Horizontal + + + + + + + true + + + + 0 + 0 + + + + 1000000 + + + 100 + + + 500 + + + + + + + Enable a second, broadcast output with a higher queue length +for better quality at the expense of latency. + + + Enable &Broadcast Output + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + true + + + This will override the queue buffer length entered in the advanced options tab. (The default value is 500.) + + + true + + + + + + + true + + + Enable the new jitter buffer. This is now the default. + + + Enable &Jitter Buffer + + + true + + + + + + + true + + + <html><head/><body><p>Buffer strategy 1 attempts to drop as little audio data as possible without exceeding the maximum queue length. It operates very similarly to the original buffer implementation with a few fixes to drop even less audio.</p><p>Buffer strategy 2 is optimized to keep the latency stable, so that the delay experienced over the connection doesn't fluctuate and is as predictable as possible. The trade off is that more audio might be dropped, but the difference should be negligible with the right queue length.</p></body></html> + + + 0 + + + + 1 + + + + + 2 + + + + + 3 (experimental) + + + + + + + + true + + + + 0 + 0 + + + + Use buffer &strategy + + + bufferStrategyComboBox + + + + + + + false + + + Broadcast &Queue Length + + + broadcastQueueSpinBox + + + + + + + false + + + Set the broadcast queue buffer length, in packet size. + + + 8 + + + + + + + + Plugins + + + + + + true + + + Incoming + + + + + + false + + + Set the wet/dry mix. + + + 100 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 20 + + + + + + + false + + + Wetness + + + + + + + Enable the limiter on incoming audio. + + + &Limiter + + + + + + + Enable the freeverb plugin on incoming audio. + + + &Freeverb + + + + + + + false + + + Wetness + + + + + + + Enable the compressor plugin on incoming audio. + + + &Compressor + + + + + + + Enable the zitarev reverb plugin on incoming audio. + + + &Zitarev + + + + + + + false + + + Set the wet/dry mix. + + + 100 + + + 1 + + + Qt::Horizontal + + + false + + + QSlider::TicksBelow + + + 20 + + + + + + + + + + true + + + Outgoing + + + + + + Enable the freeverb plugin on outgoing audio. + + + Free&verb + + + + + + + false + + + Set the wet/dry mix. + + + 100 + + + 1 + + + Qt::Horizontal + + + false + + + QSlider::TicksBelow + + + 20 + + + + + + + false + + + Wetness + + + + + + + Enable the zitarev reverb plugin on outgoing audio. + + + Zi&tarev + + + + + + + false + + + Set the wet/dry mix. + + + 100 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 20 + + + + + + + false + + + Moisture is the essence of wetness, +and wetness is the essence of beauty. + + + Wetness + + + + + + + Enable the compressor plugin on outgoing audio. + + + Com&pressor + + + + + + + Enable the limiter on outgoing audio. + + + Li&miter + + + + + + + false + + + Enter the anticipated number of clients that will be connected to the server. + + + 1 + + + 100 + + + 2 + + + + + + + false + + + Clients + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + 0 + 0 + 409 + 30 + + + + + + + typeComboBox + addressComboBox + connectButton + disconnectButton + exitButton + optionsTabWidget + channelRecvSpinBox + channelSendSpinBox + autoPatchComboBox + zeroCheckBox + timeoutCheckBox + requireAuthCheckBox + certEdit + certBrowse + keyEdit + keyBrowse + credsEdit + credsBrowse + authCheckBox + usernameEdit + passwordEdit + aboutButton + clientNameEdit + remoteNameEdit + localPortSpinBox + remotePortSpinBox + basePortSpinBox + queueLengthSpinBox + redundancySpinBox + resolutionComboBox + connectAudioCheckBox + realTimeCheckBox + ioStatsCheckBox + ioStatsSpinBox + verboseCheckBox + commandLineButton + useDefaultsButton + backendComboBox + sampleRateComboBox + bufferSizeComboBox + inputDeviceComboBox + outputDeviceComboBox + refreshDevicesButton + jitterCheckBox + bufferStrategyComboBox + broadcastCheckBox + broadcastQueueSpinBox + autoQueueCheckBox + autoQueueSpinBox + inFreeverbCheckBox + inFreeverbWetnessSlider + inZitarevCheckBox + inZitarevWetnessSlider + inCompressorCheckBox + inLimiterCheckBox + outFreeverbCheckBox + outFreeverbWetnessSlider + outZitarevCheckBox + outZitarevWetnessSlider + outCompressorCheckBox + outLimiterCheckBox + outClientsSpinBox + + + + + + diff --git a/src/gui/textbuf.cpp b/src/gui/textbuf.cpp new file mode 100644 index 0000000..0fcf1f4 --- /dev/null +++ b/src/gui/textbuf.cpp @@ -0,0 +1,68 @@ +//***************************************************************** +/* + QJackTrip: Bringing a graphical user interface to JackTrip, a + system for high quality audio network performance over the + internet. + + Copyright (c) 2021 Aaron Wyatt. + + This file is part of QJackTrip. + + QJackTrip 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, either version 3 of the License, or + (at your option) any later version. + + QJackTrip 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 for more details. + + You should have received a copy of the GNU General Public License + along with QJackTrip. If not, see . +*/ +//***************************************************************** + +#include "textbuf.h" + +void textbuf::setOutStream(std::ostream* output) +{ + m_outStream = output; +} + +int textbuf::overflow(int c) +{ + //Output our buffer. + putChars(pbase(), pptr()); + + if (c != traits_t::eof()) { + char out = c; + putChars(&out, &out + 1); + } + + //Set buffer to empty again + setp(m_buf, m_buf + BUF_SIZE); + + return c; +} + +int textbuf::sync() +{ + //Flush our buffer. + putChars(pbase(), pptr()); + setp(m_buf, m_buf + BUF_SIZE); + return 0; +} + +void textbuf::putChars(const char* begin, const char* end) +{ + if (m_outStream) { + for (const char* c = begin; c < end; c++) { + *m_outStream << *c; + } + m_outStream->flush(); + } + + emit outputString(QString(QByteArray(begin, end - begin))); +} + diff --git a/src/gui/textbuf.h b/src/gui/textbuf.h new file mode 100644 index 0000000..b0326f6 --- /dev/null +++ b/src/gui/textbuf.h @@ -0,0 +1,61 @@ +//***************************************************************** +/* + QJackTrip: Bringing a graphical user interface to JackTrip, a + system for high quality audio network performance over the + internet. + + Copyright (c) 2021 Aaron Wyatt. + + This file is part of QJackTrip. + + QJackTrip 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, either version 3 of the License, or + (at your option) any later version. + + QJackTrip 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 for more details. + + You should have received a copy of the GNU General Public License + along with QJackTrip. If not, see . +*/ +//***************************************************************** + +#ifndef TEXTBUF_H +#define TEXTBUF_H + +#include +#include +#include + +//Extension of a stream buffer to output to a QTextEdit +class textbuf : public QObject, public std::basic_streambuf> +{ + Q_OBJECT + + public: + textbuf() { setp(m_buf, m_buf + BUF_SIZE); } + + void setOutStream(std::ostream *output); + + signals: + void outputString(const QString& output); + + protected: + virtual int overflow(int c = traits_t::eof()); + virtual int sync(); + + private: + typedef std::char_traits traits_t; + + static const size_t BUF_SIZE = 64; + char m_buf[BUF_SIZE]; + + std::ostream *m_outStream = nullptr; + + void putChars(const char* begin, const char* end); +}; + +#endif // TEXTBUF_H diff --git a/src/jacktrip_globals.h b/src/jacktrip_globals.h index 2558045..6f222f7 100644 --- a/src/jacktrip_globals.h +++ b/src/jacktrip_globals.h @@ -44,7 +44,7 @@ /// \todo Add this namespace // namespace JackTrip -constexpr const char* const gVersion = "1.4.1"; ///< JackTrip version +constexpr const char* const gVersion = "1.4.2"; ///< JackTrip version //******************************************************************************* /// \name Default Values diff --git a/src/main.cpp b/src/main.cpp index 9939ca3..044af97 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -39,6 +39,7 @@ #include #include "gui/qjacktrip.h" +#include #else #include #endif @@ -51,6 +52,12 @@ #include "UdpHubListener.h" #include "jacktrip_globals.h" +#ifdef __WIN_32__ +#include +#include +#include +#endif + QCoreApplication* createApplication(int& argc, char* argv[]) { // Check for some specific, GUI related command line options. @@ -154,6 +161,49 @@ BOOL WINAPI windowsCtrlHandler(DWORD fdwCtrlType) return false; } } + +bool isRunFromCmd() { + //Get our parent process pid + HANDLE h = NULL; + PROCESSENTRY32 pe = {0}; + DWORD pid = GetCurrentProcessId(); + DWORD ppid = 0; + pe.dwSize = sizeof(PROCESSENTRY32); + h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (Process32First(h, &pe)) { + do { + //Loop through the list of processes until we find ours. + if (pe.th32ProcessID == pid) { + ppid = pe.th32ParentProcessID; + break; + } + } while (Process32Next(h, &pe)); + } + CloseHandle(h); + + //Get the name of our parent process; + char pname[MAX_PATH] = {0}; + DWORD size = MAX_PATH; + h = NULL; + h = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, ppid); + if (h) { + if (QueryFullProcessImageNameA(h, 0, pname, &size)) { + CloseHandle(h); + + //Check if our parent process is a command line. + if (size >= 14 && strncmp(pname + size - 14, "powershell.exe", 14) == 0) { + return true; + } + if (size >= 7 && strncmp(pname + size - 7, "cmd.exe", 7) == 0) { + return true; + } + } else { + CloseHandle(h); + } + } + + return false; +} #endif int main(int argc, char* argv[]) @@ -166,10 +216,21 @@ int main(int argc, char* argv[]) if (qobject_cast(app.data())) { // Start the GUI if there are no command line options. #ifdef __WIN_32__ - // Remove the console that appears if we're in windows. - FreeConsole(); + // Remove the console that appears if we're on windows and not running from a command line. + if (!isRunFromCmd()) { + FreeConsole(); + } #endif // __WIN_32__ app->setApplicationName("QJackTrip"); + + QCommandLineParser parser; + QCommandLineOption verboseOption(QStringList() << "V" << "verbose"); + parser.addOption(verboseOption); + parser.parse(app->arguments()); + if (parser.isSet(verboseOption)) { + gVerboseFlag = true; + } + window.reset(new QJackTrip); window->setArgc(argc); QObject::connect(window.data(), &QJackTrip::signalExit, app.data(), diff --git a/subprojects/rtaudio.wrap b/subprojects/rtaudio.wrap index cdb4fb2..5aeba8f 100644 --- a/subprojects/rtaudio.wrap +++ b/subprojects/rtaudio.wrap @@ -1,6 +1,9 @@ -[wrap-git] -url=https://github.com/thestk/rtaudio.git -revision=head +[wrap-file] +directory = rtaudio-5.2.0 +source_url = https://github.com/thestk/rtaudio/archive/refs/tags/5.2.0.tar.gz +source_filename = 5.2.0.tar.gz +source_hash = a8d9c738addffd485c3f0bab14cbba72600267e3113f274398c67829bbb49332 [provide] dependency_names = rtaudio + -- 2.30.2