From: Dennis Braun Date: Wed, 12 Aug 2020 14:40:55 +0000 (+0200) Subject: New upstream version 1.2.1+ds0 X-Git-Tag: archive/raspbian/2.5.1+ds-1+rpi1~1^2~9^2~30 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=217d8d2380fddcc9cc837c7820490115facff96a;p=jacktrip.git New upstream version 1.2.1+ds0 --- diff --git a/.gitignore b/.gitignore index 1afe92a..c9dcabe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ # QtCreator user files *.pro.user *.pro.user.* + +# build directory +builddir/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f551d99 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,42 @@ +os: + - linux + - osx + +language: + - cpp + +# force updated ubuntu distribution with up-to-date gcc +dist: bionic + +branches: + - master + +env: + global: + - PKGS_OSX="jack qt rt-audio" + +addons: + apt: + update: true + packages: + - qt5-default + - qttools5-dev-tools + - libjack-dev + - librtaudio-dev + +before_script: + # manually install brew packages as addon: homebrew is broken in the default osx image + - if [ "$TRAVIS_OS_NAME" = "osx" ]; then HOMEBREW_NO_AUTO_UPDATE=1 brew install $PKGS_OSX; fi + # mac: workaround for homebrew qmake not being symlinked into $PATH + # see https://stackoverflow.com/questions/48847505/why-cant-i-use-qmake-on-mac-after-installing-it + - if [ "$TRAVIS_OS_NAME" = "osx" ]; then export PATH="/usr/local/opt/qt/bin:$PATH"; fi + +script: + - cd src + - ./build + +after_success: + - echo "Success!" + +after_failure: + - echo "Something went wrong :(" diff --git a/CHANGESLOG.txt b/CHANGESLOG.txt index c8dc135..3377943 100644 --- a/CHANGESLOG.txt +++ b/CHANGESLOG.txt @@ -1,5 +1,9 @@ --- -master +1.2.1 (master) (branch name will be deprecated) +(main and dev) (new branches, respectively for stable and development) +- (added) src/build script builds in ../builddir +- (fixed) refactor "Master" to be "Hub" +- (fixed) 1.2.1 correctly versioned and tagged --- 1.2 (release candidate, not yet tagged) diff --git a/INSTALL.txt b/INSTALL.txt index 2ca1624..f8b23dc 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -103,7 +103,7 @@ $ qmake -config nojack jacktrip.pro $ make release -If you want to install (using Terminal): on the /src directory type: +If you want to install (using Terminal): on the /builddir directory type: $ sudo cp jacktrip /usr/local/bin/ (enter your password when prompted) diff --git a/INSTALL_meson.md b/INSTALL_meson.md new file mode 100644 index 0000000..fda5b39 --- /dev/null +++ b/INSTALL_meson.md @@ -0,0 +1,23 @@ +# Build and Installation Instructions with Meson + +## Install Dependencies + +Fedora: +dnf install meson qt5-qtbase-devel rtaudio-devel jack-audio-connection-kit-devel + +Debian/Ubuntu: +apt install meson build-essential qtbase5-dev librtaudio-dev libjack-jackd2-dev + +MacOS with brew (not tested): +brew install meson qt rt-audio jack + +## Build + +Prepare your build directory (by default debug and nonoptimized): +meson builddir + +Now build with: +ninja -C builddir + +Install with: +ninja -C builddir install diff --git a/JMess.cpp b/JMess.cpp index 30b20dc..2708bc4 100644 --- a/JMess.cpp +++ b/JMess.cpp @@ -167,7 +167,7 @@ void JMess::setConnectedPorts() } //******************************************************************************* void JMess::connectSpawnedPorts(int nChans, int hubPatch) -// called from UdpMasterListener::connectMesh +// called from UdpHubListener::connectMesh { QString IPS[gMAX_WAIRS]; int ctr = 0; @@ -307,7 +307,7 @@ void JMess::connectSpawnedPorts(int nChans, int hubPatch) // this is brute force, does not look at individual clients, just patches the whole ensemble // each time void JMess::connectTUB(int /*nChans*/) -// called from UdpMasterListener::connectPatch +// called from UdpHubListener::connectPatch { for (int i = 0; i<=gMAX_TUB-gMIN_TUB; i++) // last IP decimal octet for (int l = 1; l<=1; l++) // mono for now // chans are 1-based, 1...2 diff --git a/README.md b/README.md index 9490616..201635e 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ And as of spring 2020 it moved back to GitHub for the current development. ## Links ## * Preliminary [Documentation](http://ccrma.stanford.edu/groups/soundwire/software/jacktrip/) and [API](http://ccrma.stanford.edu/groups/soundwire/software/jacktrip/annotated.html). * Subscribe to the [Mailing List](http://groups.google.com/group/jacktrip-users). - * [CCRMA](http://ccrma.stanford.edu/) . + * [CCRMA](http://ccrma.stanford.edu/). * [SoundWIRE group](http://ccrma.stanford.edu/groups/soundwire/). * [Juan-Pablo Caceres](https://ccrma.stanford.edu/~jcaceres/). diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..6debd45 --- /dev/null +++ b/meson.build @@ -0,0 +1,45 @@ +project('jacktrip', 'cpp', version: '1.2') +qt5 = import('qt5') +qt5_dep = dependency('qt5', modules: ['Core', 'Network']) +jack_dep = dependency('jack') +rtaudio_dep = dependency('rtaudio') +thread_dep = dependency('threads') + +defines = [] +if host_machine.system() == 'linux' + defines += '-D__LINUX__' +elif host_machine.system() == 'osx' + defines += '-D__MAC_OSX__' +elif host_machine.system() == 'windows' + defines += '-D__WIN_32__' +endif + +moc_h = ['src/DataProtocol.h', + 'src/JackTrip.h', + 'src/JackTripWorker.h', + 'src/JackTripWorkerMessages.h', + 'src/NetKS.h', + 'src/PacketHeader.h', + 'src/Settings.h', + 'src/UdpDataProtocol.h', + 'src/UdpHubListener.h'] +moc_files = qt5.preprocess(moc_headers : moc_h) + +src = ['src/DataProtocol.cpp', + 'src/JMess.cpp', + 'src/JackTrip.cpp', + 'src/jacktrip_globals.cpp', + 'src/jacktrip_main.cpp', + 'src/JackTripThread.cpp', + 'src/JackTripWorker.cpp', + 'src/LoopBack.cpp', + 'src/PacketHeader.cpp', + 'src/ProcessPlugin.cpp', + 'src/RingBuffer.cpp', + 'src/Settings.cpp', + 'src/UdpDataProtocol.cpp', + 'src/UdpHubListener.cpp', + 'src/AudioInterface.cpp', + 'src/JackAudioInterface.cpp'] + +executable('jacktrip', src, moc_files, dependencies: [qt5_dep, jack_dep, rtaudio_dep, thread_dep], cpp_args: defines, install: true ) diff --git a/src/DataProtocol.h b/src/DataProtocol.h index 816e6a8..413263d 100644 --- a/src/DataProtocol.h +++ b/src/DataProtocol.h @@ -171,6 +171,15 @@ public: virtual void setSocket(int &socket) = 0; #endif + struct PktStat { + uint32_t tot; + uint32_t lost; + uint32_t outOfOrder; + uint32_t revived; + uint32_t statCount; + }; + virtual bool getStats(PktStat*) {return false;} + signals: void signalError(const char* error_message); diff --git a/src/JMess.cpp b/src/JMess.cpp index b49008c..8cdab74 100644 --- a/src/JMess.cpp +++ b/src/JMess.cpp @@ -35,6 +35,8 @@ #include "jacktrip_globals.h" #include +// sJackMutex definition +QMutex JMess::sJMessMutex; //------------------------------------------------------------------------------- /*! \brief Constructs a JMess object that has a jack client. @@ -167,8 +169,11 @@ void JMess::setConnectedPorts() } //******************************************************************************* void JMess::connectSpawnedPorts(int nChans, int hubPatch) -// called from UdpMasterListener::connectMesh +// called from UdpHubListener::connectMesh { + + QMutexLocker locker(&sJMessMutex); + QString IPS[gMAX_WAIRS]; int ctr = 0; @@ -197,7 +202,7 @@ void JMess::connectSpawnedPorts(int nChans, int hubPatch) // qDebug() << ports[out_i] << systemPort << s; } } - for (int i = 0; i //#include //#include +#include #include @@ -87,5 +88,6 @@ private: //OuputPortN InputPortN QVector > mConnectedPorts; QVector > mPortsToConnect; + static QMutex sJMessMutex; ///< Mutex to make thread safe jack functions that are not }; #endif diff --git a/src/JackTrip.cpp b/src/JackTrip.cpp index 85d91cd..c425851 100644 --- a/src/JackTrip.cpp +++ b/src/JackTrip.cpp @@ -52,6 +52,8 @@ #include #include #include +#include +#include using std::cout; using std::endl; @@ -104,12 +106,13 @@ JackTrip::JackTrip(jacktripModeT JacktripMode, mReceiverPeerPort(receiver_peer_port), mTcpServerPort(4464), mRedundancy(redundancy), - mJackClientName("JackTrip"), + mJackClientName(gJackDefaultClientName), mConnectionMode(JackTrip::NORMAL), mReceivedConnection(false), mTcpConnectionError(false), mStopped(false), - mConnectDefaultAudioPorts(true) + mConnectDefaultAudioPorts(true), + mIOStatLogStream(std::cout.rdbuf()) { createHeader(mPacketHeaderType); } @@ -130,7 +133,7 @@ JackTrip::~JackTrip() //******************************************************************************* void JackTrip::setupAudio( - #ifdef WAIRTOMASTER // WAIR + #ifdef WAIRTOHUB // WAIR int ID #endif // endwhere ) @@ -153,15 +156,14 @@ void JackTrip::setupAudio( #endif // endwhere mAudioBitResolution); -#ifdef WAIRTOMASTER // WAIR - qDebug() << "mPeerAddress" << mPeerAddress << mPeerAddress.contains(gDOMAIN_TRIPLE); - QString VARIABLE_AUDIO_NAME = WAIR_AUDIO_NAME; // legacy for WAIR - QByteArray tmp = QString(mPeerAddress).replace(":", ".").toLatin1(); - if(mPeerAddress.toStdString()!="") - mJackClientName = tmp.constData(); - std::cout << "WAIR ID " << ID << " jacktrip client name set to=" << - mJackClientName << std::endl; - +#ifdef WAIRTOHUB // WAIR + //Set our Jack client name if we're a hub server or a custom name hasn't been set + if ( mPeerAddress.toStdString() != "" && + (mJackClientName == gJackDefaultClientName || mJackTripMode == SERVERPINGSERVER)) { + mJackClientName = QString(mPeerAddress).replace(":", ".").toLatin1().constData(); + } +// std::cout << "WAIR ID " << ID << " jacktrip client name set to=" << +// mJackClientName << std::endl; #endif // endwhere mAudioInterface->setClientName(mJackClientName); @@ -316,10 +318,10 @@ void JackTrip::appendProcessPlugin(ProcessPlugin* plugin) //******************************************************************************* void JackTrip::startProcess( - #ifdef WAIRTOMASTER // WAIR + #ifdef WAIRTOHUB // WAIR int ID #endif // endwhere - ) throw(std::invalid_argument) + ) { //signal that catches ctrl c in rtaudio-asio mode #if defined (__WIN_32__) if (signal(SIGINT, sigint_handler) == SIG_ERR) { @@ -333,10 +335,8 @@ void JackTrip::startProcess( if (gVerboseFlag) std::cout << " JackTrip:startProcess before checkIfPortIsBinded(mReceiverBindPort)" << std::endl; #if defined __WIN_32__ - //cc fixed windows crash with this print statement! - qDebug() << "before mJackTrip->startProcess" - << mReceiverBindPort<< mSenderBindPort; - // msleep(2000); + //cc fixed windows crash with this print statement! hope to delete +// qDebug() << "before mJackTrip->startProcess" << mReceiverBindPort<< mSenderBindPort; #endif checkIfPortIsBinded(mReceiverBindPort); if (gVerboseFlag) std::cout << " JackTrip:startProcess before checkIfPortIsBinded(mSenderBindPort)" << std::endl; @@ -345,7 +345,7 @@ void JackTrip::startProcess( // ------------------------------ if (gVerboseFlag) std::cout << " JackTrip:startProcess before setupAudio" << std::endl; setupAudio( - #ifdef WAIRTOMASTER // wair + #ifdef WAIRTOHUB // wair ID #endif // endwhere ); @@ -437,6 +437,54 @@ void JackTrip::startProcess( if (mConnectDefaultAudioPorts) { mAudioInterface->connectDefaultPorts(); } } +//******************************************************************************* +void JackTrip::startIOStatTimer(int timeout_sec, const std::ostream& log_stream) +{ + mIOStatLogStream.rdbuf(log_stream.rdbuf()); + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(onStatTimer())); + timer->start(timeout_sec*1000); +} + +//******************************************************************************* +void JackTrip::onStatTimer() +{ + DataProtocol::PktStat pkt_stat; + if (!mDataProtocolReceiver->getStats(&pkt_stat)) { + return; + } + bool reset = (0 == pkt_stat.statCount); + RingBuffer::IOStat recv_io_stat; + if (!mReceiveRingBuffer->getStats(&recv_io_stat, reset)) { + return; + } + RingBuffer::IOStat send_io_stat; + if (!mSendRingBuffer->getStats(&send_io_stat, reset)) { + return; + } + QString now = QDateTime::currentDateTime().toString(Qt::ISODate); + int32_t skew = recv_io_stat.underruns - recv_io_stat.overflows + - pkt_stat.lost + pkt_stat.revived; + + static QMutex mutex; + QMutexLocker locker(&mutex); + mIOStatLogStream << now.toLocal8Bit().constData() + << " " << getPeerAddress().toLocal8Bit().constData() + << " send: " + << send_io_stat.underruns + << "/" << send_io_stat.overflows + << " recv: " + << recv_io_stat.underruns + << "/" << recv_io_stat.overflows + << " prot: " + << pkt_stat.lost + << "/" << pkt_stat.outOfOrder + << "/" << pkt_stat.revived + << " tot: " + << pkt_stat.tot + << " skew: " << skew + << endl; +} //******************************************************************************* void JackTrip::stop() @@ -470,7 +518,7 @@ void JackTrip::waitThreads() //******************************************************************************* -void JackTrip::clientStart() throw(std::invalid_argument) +void JackTrip::clientStart() { // For the Client mode, the peer (or server) address has to be specified by the user if ( mPeerAddress.isEmpty() ) { @@ -487,7 +535,6 @@ void JackTrip::clientStart() throw(std::invalid_argument) //******************************************************************************* int JackTrip::serverStart(bool timeout, int udpTimeout) // udpTimeout unused -throw(std::invalid_argument, std::runtime_error) { // Set the peer address if ( !mPeerAddress.isEmpty() ) { @@ -584,7 +631,7 @@ throw(std::invalid_argument, std::runtime_error) //******************************************************************************* -int JackTrip::clientPingToServerStart() throw(std::invalid_argument) +int JackTrip::clientPingToServerStart() { //mConnectionMode = JackTrip::KSTRONG; //mConnectionMode = JackTrip::JAMTEST; diff --git a/src/JackTrip.h b/src/JackTrip.h index aa00a2c..594e22a 100644 --- a/src/JackTrip.h +++ b/src/JackTrip.h @@ -161,10 +161,10 @@ public: /// \brief Start the processing threads virtual void startProcess( - #ifdef WAIRTOMASTER // wair + #ifdef WAIRTOHUB // wair int ID #endif // endwhere - ) throw(std::invalid_argument); + ); /// \brief Stop the processing threads virtual void stop(); @@ -392,6 +392,8 @@ public: void printTextTest() {std::cout << "=== JackTrip PRINT ===" << std::endl;} void printTextTest2() {std::cout << "=== JackTrip PRINT2 ===" << std::endl;} + void startIOStatTimer(int timeout_sec, const std::ostream& log_stream); + public slots: /// \brief Slot to stop all the processes and threads virtual void slotStopProcesses() @@ -418,6 +420,7 @@ public slots: { std::cout << "=== TESTING ===" << std::endl; } void slotReceivedConnectionFromPeer() { mReceivedConnection = true; } + void onStatTimer(); signals: @@ -434,7 +437,7 @@ public: /// \brief Set the AudioInteface object virtual void setupAudio( - #ifdef WAIRTOMASTER // WAIR + #ifdef WAIRTOHUB // WAIR int ID #endif // endwhere ); @@ -445,16 +448,15 @@ public: /// \brief Set the RingBuffer objects void setupRingBuffers(); /// \brief Starts for the CLIENT mode - void clientStart() throw(std::invalid_argument); + void clientStart(); /// \brief Starts for the SERVER mode /// \param timout Set the server to timeout after 2 seconds if no client connections are received. /// Usefull for the multithreaded server /// \return 0 on success, -1 on error - int serverStart(bool timeout = false, int udpTimeout = gTimeOutMultiThreadedServer) - throw(std::invalid_argument, std::runtime_error); + int serverStart(bool timeout = false, int udpTimeout = gTimeOutMultiThreadedServer); /// \brief Stats for the Client to Ping Server /// \return -1 on error, 0 on success - virtual int clientPingToServerStart() throw(std::invalid_argument); + virtual int clientPingToServerStart(); private: //void bindReceiveSocket(QUdpSocket& UdpSocket, int bind_port, @@ -510,6 +512,7 @@ private: volatile bool mStopped; bool mConnectDefaultAudioPorts; ///< Connect or not default audio ports + std::ostream mIOStatLogStream; }; #endif diff --git a/src/JackTripWorker.cpp b/src/JackTripWorker.cpp index 84b825f..f006261 100644 --- a/src/JackTripWorker.cpp +++ b/src/JackTripWorker.cpp @@ -44,9 +44,10 @@ #include "JackTripWorker.h" #include "JackTrip.h" -#include "UdpMasterListener.h" +#include "UdpHubListener.h" #include "NetKS.h" #include "LoopBack.h" +#include "Settings.h" #ifdef WAIR // wair #include "dcblock2gain.dsp.h" #endif // endwhere @@ -57,8 +58,8 @@ using std::cout; using std::endl; //******************************************************************************* -JackTripWorker::JackTripWorker(UdpMasterListener* udpmasterlistener, int BufferQueueLength, JackTrip::underrunModeT UnderRunMode) : - mUdpMasterListener(udpmasterlistener), +JackTripWorker::JackTripWorker(UdpHubListener* udpmasterlistener, int BufferQueueLength, JackTrip::underrunModeT UnderRunMode) : + mUdpHubListener(udpmasterlistener), m_connectDefaultAudioPorts(false), mBufferQueueLength(BufferQueueLength), mUnderRunMode(UnderRunMode), @@ -79,7 +80,7 @@ JackTripWorker::JackTripWorker(UdpMasterListener* udpmasterlistener, int BufferQ //******************************************************************************* JackTripWorker::~JackTripWorker() { - //delete mUdpMasterListener; + //delete mUdpHubListener; } @@ -127,13 +128,14 @@ void JackTripWorker::run() // Create and setup JackTrip Object //JackTrip jacktrip(JackTrip::SERVER, JackTrip::UDP, mNumChans, 2); if (gVerboseFlag) cout << "---> JackTripWorker: Creating jacktrip objects..." << endl; + Settings* settings = mUdpHubListener->getSettings(); #ifdef WAIR // WAIR // forces BufferQueueLength to 2 // need to parse numNetChans from incoming header // but force to 16 for now #define FORCEBUFFERQ 2 - if (mUdpMasterListener->isWAIR()) { // invoked with -Sw + if (mUdpHubListener->isWAIR()) { // invoked with -Sw mWAIR = true; mNumNetRevChans = NUMNETREVCHANSbecauseNOTINRECEIVEDheader; } else {}; @@ -208,7 +210,7 @@ void JackTripWorker::run() if (gVerboseFlag) cout << "---> JackTripWorker: setJackTripFromClientHeader..." << endl; int PeerConnectionMode = setJackTripFromClientHeader(jacktrip); if ( PeerConnectionMode == -1 ) { - mUdpMasterListener->releaseThread(mID); + mUdpHubListener->releaseThread(mID); { QMutexLocker locker(&mMutex); mSpawning = false; } return; } @@ -216,10 +218,13 @@ void JackTripWorker::run() // Start Threads and event loop if (gVerboseFlag) cout << "---> JackTripWorker: startProcess..." << endl; jacktrip.startProcess( - #ifdef WAIRTOMASTER // wair + #ifdef WAIRTOHUB // wair mID #endif // endwhere ); + if (0 != settings->getIOStatTimeout()) { + jacktrip.startIOStatTimer(settings->getIOStatTimeout(), settings->getIOStatStream()); + } // if (gVerboseFlag) cout << "---> JackTripWorker: start..." << endl; // jacktrip.start(); // ########### JamTest Only ################# @@ -240,14 +245,14 @@ void JackTripWorker::run() std::cerr << "Couldn't send thread to the Pool" << endl; std::cerr << e.what() << endl; std::cerr << gPrintSeparator << endl; - mUdpMasterListener->releaseThread(mID); + mUdpHubListener->releaseThread(mID); { QMutexLocker locker(&mMutex); mSpawning = false; } return; } { QMutexLocker locker(&mMutex); - mUdpMasterListener->releaseThread(mID); + mUdpHubListener->releaseThread(mID); } cout << "JackTrip ID = " << mID << " released from the THREAD POOL" << endl; diff --git a/src/JackTripWorker.h b/src/JackTripWorker.h index 06760e5..62c65da 100644 --- a/src/JackTripWorker.h +++ b/src/JackTripWorker.h @@ -50,7 +50,7 @@ #include "jacktrip_globals.h" //class JackTrip; // forward declaration -class UdpMasterListener; // forward declaration +class UdpHubListener; // forward declaration /** \brief Prototype of the worker class that will be cloned through sending threads to the @@ -70,7 +70,7 @@ class JackTripWorker : public QObject, public QRunnable public: /// \brief The class constructor - JackTripWorker(UdpMasterListener* udpmasterlistener, int BufferQueueLength = gDefaultQueueLength, JackTrip::underrunModeT UnderRunMode = JackTrip::WAVETABLE); + JackTripWorker(UdpHubListener* udpmasterlistener, int BufferQueueLength = gDefaultQueueLength, JackTrip::underrunModeT UnderRunMode = JackTrip::WAVETABLE); /// \brief The class destructor virtual ~JackTripWorker(); @@ -111,7 +111,7 @@ private: int setJackTripFromClientHeader(JackTrip& jacktrip); JackTrip::connectionModeT getConnectionModeFromHeader(); - UdpMasterListener* mUdpMasterListener; ///< Master Listener Socket + UdpHubListener* mUdpHubListener; ///< Hub Listener Socket //QHostAddress mClientAddress; ///< Client Address QString mClientAddress; uint16_t mServerPort; ///< Server Ephemeral Incomming Port to use with Client diff --git a/src/RingBuffer.cpp b/src/RingBuffer.cpp index 5b95161..124399e 100644 --- a/src/RingBuffer.cpp +++ b/src/RingBuffer.cpp @@ -86,6 +86,8 @@ RingBuffer::RingBuffer(int SlotSize, int NumSlots) : mWritePosition = ( (NumSlots/2) * SlotSize ) % mTotalSize; // Udpate Full Slots accordingly mFullSlots = (NumSlots/2); + mUnderruns = 0; + mOverflows = 0; } @@ -226,6 +228,7 @@ void RingBuffer::underrunReset() //mFullSlots += mNumSlots/2; // There's nothing new to read, so we clear the whole buffer (Set the entire buffer to 0) std::memset(mRingBuffer, 0, mTotalSize); + ++mUnderruns; } @@ -237,6 +240,7 @@ void RingBuffer::overflowReset() //mReadPosition = ( mWritePosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize; mReadPosition = ( mReadPosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize; mFullSlots -= mNumSlots/2; + mOverflows += mNumSlots/2 + 1; } @@ -248,3 +252,15 @@ void RingBuffer::debugDump() const cout << "mWritePosition = " << mWritePosition << endl; cout << "mFullSlots = " << mFullSlots << endl; } + +//******************************************************************************* +bool RingBuffer::getStats(RingBuffer::IOStat* stat, bool reset) +{ + if (reset) { + mUnderruns = 0; + mOverflows = 0; + } + stat->underruns = mUnderruns; + stat->overflows = mOverflows; + return true; +} diff --git a/src/RingBuffer.h b/src/RingBuffer.h index 5da8208..78e137f 100644 --- a/src/RingBuffer.h +++ b/src/RingBuffer.h @@ -44,6 +44,8 @@ #include "jacktrip_types.h" +#include + //using namespace JackTripNamespace; @@ -100,6 +102,11 @@ public: */ void readSlotNonBlocking(int8_t* ptrToReadSlot); + struct IOStat { + uint32_t underruns; + uint32_t overflows; + }; + virtual bool getStats(IOStat* stat, bool reset); protected: @@ -139,6 +146,8 @@ private: QMutex mMutex; ///< Mutex to protect read and write operations QWaitCondition mBufferIsNotFull; ///< Buffer not full condition to monitor threads QWaitCondition mBufferIsNotEmpty; ///< Buffer not empty condition to monitor threads + std::atomic mUnderruns; + std::atomic mOverflows; }; #endif diff --git a/src/Settings.cpp b/src/Settings.cpp index 25caf47..541ee8a 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -44,7 +44,7 @@ #include "Stk16.dsp.h" #endif // endwhere -#include "UdpMasterListener.h" +#include "UdpHubListener.h" #include "JackTripWorker.h" #include "jacktrip_globals.h" @@ -85,7 +85,8 @@ Settings::Settings() : mChanfeDefaultID(0), mChanfeDefaultBS(false), mHubConnectionMode(JackTrip::SERVERTOCLIENT), - mConnectDefaultAudioPorts(true) + mConnectDefaultAudioPorts(true), + mIOStatTimeout(0) {} //******************************************************************************* @@ -140,6 +141,8 @@ void Settings::parseInput(int argc, char** argv) { "version", no_argument, NULL, 'v' }, // Version Number { "verbose", no_argument, NULL, 'V' }, // Verbose mode { "hubpatch", required_argument, NULL, 'p' }, // Set hubConnectionMode for auto patch in Jack + { "iostat", required_argument, NULL, 'I' }, // Set IO stat timeout + { "iostatlog", required_argument, NULL, 'G' }, // Set IO stat log file { "help", no_argument, NULL, 'h' }, // Print Help { NULL, 0, NULL, 0 } }; @@ -288,7 +291,7 @@ void Settings::parseInput(int argc, char** argv) case 'v': //------------------------------------------------------- cout << "JackTrip VERSION: " << gVersion << endl; - cout << "Copyright (c) 2008-2018 Juan-Pablo Caceres, Chris Chafe." << endl; + cout << "Copyright (c) 2008-2020 Juan-Pablo Caceres, Chris Chafe." << endl; cout << "SoundWIRE group at CCRMA, Stanford University" << endl; cout << "" << endl; std::exit(0); @@ -316,6 +319,25 @@ void Settings::parseInput(int argc, char** argv) printUsage(); std::exit(1); } break; + case 'I': // IO Stat timeout + //------------------------------------------------------- + mIOStatTimeout = atoi(optarg); + if (0 > mIOStatTimeout) { + std::cerr << "--iostat ERROR: negative timeout." << endl; + printUsage(); + std::exit(1); + } + break; + case 'G': // IO Stat log file + //------------------------------------------------------- + mIOStatStream.open(optarg); + if (!mIOStatStream.is_open()) { + std::cerr << "--iostatlog FAILED to open " << optarg + << " for writing." << endl; + printUsage(); + std::exit(1); + } + break; case 'h': //------------------------------------------------------- printUsage(); @@ -349,7 +371,7 @@ void Settings::printUsage() cout << "" << endl; cout << "JackTrip: A System for High-Quality Audio Network Performance" << endl; cout << "over the Internet" << endl; - cout << "Copyright (c) 2008-2018 Juan-Pablo Caceres, Chris Chafe." << endl; + cout << "Copyright (c) 2008-2020 Juan-Pablo Caceres, Chris Chafe." << endl; cout << "SoundWIRE group at CCRMA, Stanford University" << endl; cout << "VERSION: " << gVersion << endl; cout << "" << endl; @@ -386,7 +408,7 @@ void Settings::printUsage() cout << " -j, --jamlink Run in JamLink Mode (Connect to a JamLink Box)" << endl; cout << " --clientname Change default client name (default: JackTrip)" << endl; cout << " --localaddress Change default local host IP address (default: 127.0.0.1)" << endl; - cout << " --nojackportsconnect Don't connect default audio ports in jack" << endl; + cout << " --nojackportsconnect Don't connect default audio ports in jack, including not doing hub auto audio patch in HUB SERVER mode." << endl; cout << endl; cout << "ARGUMENTS TO USE JACKTRIP WITHOUT JACK:" << endl; cout << " --rtaudio Use system's default sound system instead of Jack" << endl; @@ -394,6 +416,10 @@ void Settings::printUsage() cout << " --bufsize # Set the buffer size, works on --rtaudio mode only (default: 128)" << endl; cout << " --deviceid # The rtaudio device id --rtaudio mode only (default: 0)" << endl; cout << endl; + cout << "ARGUMENTS TO DISPLAY IO STATISTICS:" << endl; + cout << " --iostat Turn on IO stat reporting with specified interval (in seconds)" << endl; + cout << " --iostatlog Save stat log into a file (default: print in stdout)" << endl; + cout << endl; cout << "HELP ARGUMENTS: " << endl; cout << " -v, --version Prints Version Number" << endl; cout << " -V, --verbose Verbose mode, prints debug messages" << endl; @@ -408,7 +434,8 @@ void Settings::startJackTrip() /// \todo Change this, just here to test if ( mJackTripServer ) { - UdpMasterListener* udpmaster = new UdpMasterListener; + UdpHubListener* udpmaster = new UdpHubListener; + udpmaster->setSettings(this); #ifdef WAIR // WAIR udpmaster->setWAIR(mWAIR); #endif // endwhere @@ -569,10 +596,13 @@ void Settings::startJackTrip() // Start JackTrip if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->startProcess" << std::endl; mJackTrip->startProcess( - #ifdef WAIRTOMASTER // WAIR + #ifdef WAIRTOHUB // WAIR 0 // for WAIR compatibility, ID in jack client name #endif // endwhere ); + if (0 < getIOStatTimeout()) { + mJackTrip->startIOStatTimer(getIOStatTimeout(), getIOStatStream()); + } // if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->start" << std::endl; // this is a noop // mJackTrip->start(); diff --git a/src/Settings.h b/src/Settings.h index 9272755..dba212e 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -40,6 +40,7 @@ #define __SETTINGS_H__ #include +#include #include "DataProtocol.h" @@ -69,6 +70,11 @@ public: void printUsage(); bool getLoopBack() { return mLoopBack; } + int getIOStatTimeout() const {return mIOStatTimeout;} + const std::ostream& getIOStatStream() const + { + return mIOStatStream.is_open() ? (std::ostream&)mIOStatStream : std::cout; + } public slots: @@ -113,6 +119,8 @@ private: unsigned int mAudioBufferSize; unsigned int mHubConnectionMode; bool mConnectDefaultAudioPorts; ///< Connect or not jack audio ports + int mIOStatTimeout; + std::ofstream mIOStatStream; }; #endif diff --git a/src/UdpDataProtocol.cpp b/src/UdpDataProtocol.cpp index b08ae9e..85738a6 100644 --- a/src/UdpDataProtocol.cpp +++ b/src/UdpDataProtocol.cpp @@ -51,7 +51,7 @@ #include //cc need SD_SEND #include // for IPv6 #endif -#if defined (__LINUX__) || (__MAC__OSX__) +#if defined (__LINUX__) || (__MAC_OSX__) #include // for POSIX Sockets #endif @@ -98,10 +98,10 @@ UdpDataProtocol::~UdpDataProtocol() //******************************************************************************* -void UdpDataProtocol::setPeerAddress(const char* peerHostOrIP) throw(std::invalid_argument) +void UdpDataProtocol::setPeerAddress(const char* peerHostOrIP) { // Get DNS Address -#if defined (__LINUX__) || (__MAC__OSX__) +#if defined (__LINUX__) || (__MAC_OSX__) //Don't make the following code conditional on windows //(Addresses a weird timing bug when in hub client mode) if (!mPeerAddress.setAddress(peerHostOrIP)) { @@ -113,7 +113,7 @@ void UdpDataProtocol::setPeerAddress(const char* peerHostOrIP) throw(std::invali } //cout << "UdpDataProtocol::setPeerAddress IP Address Number: " // << mPeerAddress.toString().toStdString() << endl; -#if defined (__LINUX__) || (__MAC__OSX__) +#if defined (__LINUX__) || (__MAC_OSX__) } #endif @@ -151,9 +151,9 @@ void UdpDataProtocol::setPeerAddress(const char* peerHostOrIP) throw(std::invali } #if defined (__WIN_32__) -void UdpDataProtocol::setSocket(SOCKET &socket) throw(std::runtime_error) +void UdpDataProtocol::setSocket(SOCKET &socket) #else -void UdpDataProtocol::setSocket(int &socket) throw(std::runtime_error) +void UdpDataProtocol::setSocket(int &socket) #endif { //If we haven't been passed a valid socket, then we should bind one. @@ -176,9 +176,9 @@ void UdpDataProtocol::setSocket(int &socket) throw(std::runtime_error) //******************************************************************************* #if defined (__WIN_32__) -SOCKET UdpDataProtocol::bindSocket() throw(std::runtime_error) +SOCKET UdpDataProtocol::bindSocket() #else -int UdpDataProtocol::bindSocket() throw(std::runtime_error) +int UdpDataProtocol::bindSocket() #endif { QMutexLocker locker(&sUdpMutex); @@ -188,7 +188,7 @@ int UdpDataProtocol::bindSocket() throw(std::runtime_error) WSADATA wsaData; int err; - wVersionRequested = MAKEWORD( 1, 1 ); + wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { @@ -200,8 +200,8 @@ int UdpDataProtocol::bindSocket() throw(std::runtime_error) // Confirm that the Windows Sockets DLL supports 1.1. or higher - if ( LOBYTE( wsaData.wVersion ) != 1 || - HIBYTE( wsaData.wVersion ) != 1 ) { + if ( LOBYTE( wsaData.wVersion ) != 2 || + HIBYTE( wsaData.wVersion ) != 2 ) { // Tell the user that we couldn't find a useable // winsock.dll. WSACleanup( ); @@ -535,6 +535,11 @@ void UdpDataProtocol::run() uint16_t current_seq_num = 0; // Store current sequence number uint16_t last_seq_num = 0; // Store last package sequence number uint16_t newer_seq_num = 0; // Store newer sequence number + mTotCount = 0; + mLostCount = 0; + mOutOfOrderCount = 0; + mRevivedCount = 0; + mStatCount = 0; if (gVerboseFlag) std::cout << "step 8" << std::endl; while ( !mStopped ) @@ -571,9 +576,6 @@ void UdpDataProtocol::run() break; } case SENDER : { - //Make sure we don't start sending packets too soon. - QThread::msleep(100); - //----------------------------------------------------------------------------------- while ( !mStopped ) { // OLD CODE WITHOUT REDUNDANCY ----------------------------------------------------- @@ -632,7 +634,7 @@ void UdpDataProtocol::printUdpWaitedTooLong(int wait_msec) { int wait_time = 30; // msec if ( !(wait_msec%wait_time) ) { - std::cerr << "UDP waiting too long (more than " << wait_time << "ms)..." << endl; + std::cerr << "UDP waiting too long (more than " << wait_time << "ms) for " << mPeerAddress.toString().toStdString() << "..." << endl; } } @@ -655,6 +657,18 @@ void UdpDataProtocol::receivePacketRedundancy(QUdpSocket& UdpSocket, mJackTrip->getPeerSequenceNumber(full_redundant_packet); current_seq_num = newer_seq_num; + if (0 != last_seq_num) { + int16_t lost = newer_seq_num - last_seq_num - 1; + if (0 > lost) { + // Out of order packet, should be ignored + ++mOutOfOrderCount; + return; + } + else if (0 != lost) { + mLostCount += lost; + } + mTotCount += 1 + lost; + } //cout << current_seq_num << " "; int redun_last_index = 0; @@ -670,6 +684,7 @@ void UdpDataProtocol::receivePacketRedundancy(QUdpSocket& UdpSocket, mJackTrip->getPeerSequenceNumber( full_redundant_packet + (i*full_packet_size) ); //cout << current_seq_num << " "; } + mRevivedCount += redun_last_index; //cout << endl; last_seq_num = newer_seq_num; // Save last read packet @@ -684,6 +699,22 @@ void UdpDataProtocol::receivePacketRedundancy(QUdpSocket& UdpSocket, } } +//******************************************************************************* +bool UdpDataProtocol::getStats(DataProtocol::PktStat* stat) +{ + if (0 == mStatCount) { + mLostCount = 0; + mOutOfOrderCount = 0; + mRevivedCount = 0; + } + stat->tot = mTotCount; + stat->lost = mLostCount; + stat->outOfOrder = mOutOfOrderCount; + stat->revived = mRevivedCount; + stat->statCount = mStatCount++; + return true; +} + //******************************************************************************* void UdpDataProtocol::sendPacketRedundancy(int8_t* full_redundant_packet, int full_redundant_packet_size, diff --git a/src/UdpDataProtocol.h b/src/UdpDataProtocol.h index 2d09fe3..13d58f9 100644 --- a/src/UdpDataProtocol.h +++ b/src/UdpDataProtocol.h @@ -87,12 +87,12 @@ public: /** \brief Set the Peer address to connect to * \param peerHostOrIP IPv4 number or host name */ - void setPeerAddress(const char* peerHostOrIP) throw(std::invalid_argument); + void setPeerAddress(const char* peerHostOrIP); #if defined (__WIN_32__) - void setSocket(SOCKET &socket) throw(std::runtime_error); + void setSocket(SOCKET &socket); #else - void setSocket(int &socket) throw(std::runtime_error); + void setSocket(int &socket); #endif /** \brief Receives a packet. It blocks until a packet is received @@ -142,6 +142,7 @@ public: */ virtual void run(); + virtual bool getStats(PktStat* stat); private slots: void printUdpWaitedTooLong(int wait_msec); @@ -160,9 +161,9 @@ protected: /** \brief Binds the UDP socket to the available address and specified port */ #if defined (__WIN_32__) - SOCKET bindSocket() throw(std::runtime_error); + SOCKET bindSocket(); #else - int bindSocket() throw(std::runtime_error); + int bindSocket(); #endif /** \brief This function blocks until data is available for reading in the @@ -214,6 +215,12 @@ private: unsigned int mUdpRedundancyFactor; ///< Factor of redundancy static QMutex sUdpMutex; ///< Mutex to make thread safe the binding process + + std::atomic mTotCount; + std::atomic mLostCount; + std::atomic mOutOfOrderCount; + std::atomic mRevivedCount; + uint32_t mStatCount; }; #endif // __UDPDATAPROTOCOL_H__ diff --git a/src/UdpHubListener.cpp b/src/UdpHubListener.cpp new file mode 100644 index 0000000..b69b7b1 --- /dev/null +++ b/src/UdpHubListener.cpp @@ -0,0 +1,486 @@ +//***************************************************************** +/* + JackTrip: A System for High-Quality Audio Network Performance + over the Internet + + Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe. + SoundWIRE group at CCRMA, Stanford University. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. +*/ +//***************************************************************** + +/** + * \file UdpHubListener.cpp + * \author Juan-Pablo Caceres and Chris Chafe + * \date September 2008 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "UdpHubListener.h" +#include "JackTripWorker.h" +#include "jacktrip_globals.h" + +using std::cout; using std::endl; + + +//******************************************************************************* +UdpHubListener::UdpHubListener(int server_port) : + //mJTWorker(NULL), + mServerPort(server_port), + mStopped(false), + #ifdef WAIR // wair + mWAIR(false), + #endif // endwhere + mTotalRunningThreads(0), + m_connectDefaultAudioPorts(false) +{ + // Register JackTripWorker with the master listener + //mJTWorker = new JackTripWorker(this); + mJTWorkers = new QVector; + for (int i = 0; iinsert(i, NULL); + } + + qDebug() << "mThreadPool default maxThreadCount =" << mThreadPool.maxThreadCount(); + mThreadPool.setMaxThreadCount(mThreadPool.maxThreadCount() * 16); + qDebug() << "mThreadPool maxThreadCount set to" << mThreadPool.maxThreadCount(); + + //mJTWorkers = new JackTripWorker(this); + mThreadPool.setExpiryTimeout(3000); // msec (-1) = forever + // Inizialize IP addresses + for (int i = 0; iat(i); + } + delete mJTWorkers; +} + + +//******************************************************************************* +// Now that the first handshake is with TCP server, if the addreess/peer port of +// the client is already on the thread pool, it means that a new connection is +// requested (the old was desconnected). So we have to remove that thread from +// the pool and then connect again. +void UdpHubListener::run() +{ + mStopped = false; + + QHostAddress PeerAddress; // Object to store peer address + int peer_udp_port; // Peer listening port + int server_udp_port; // Server assigned udp port + + // Create and bind the TCP server + // ------------------------------ + QTcpServer TcpServer; + if ( !TcpServer.listen(QHostAddress::Any, mServerPort) ) { + std::cerr << "TCP Socket Server ERROR: " << TcpServer.errorString().toStdString() << endl; + std::exit(1); + } + + const int tcpTimeout = 5*1000; + + + cout << "JackTrip HUB SERVER: TCP Server Listening in Port = " << TcpServer.serverPort() << endl; + while ( !mStopped ) + { + cout << "JackTrip HUB SERVER: Waiting for client connections..." << endl; + if(m_connectDefaultAudioPorts) + { + cout << "JackTrip HUB SERVER: Hub auto audio patch setting = " << mHubPatch << endl; + } else { + cout << "JackTrip HUB SERVER: Hub auto audio patch disabled " << endl; + } + cout << "=======================================================" << endl; + while ( !TcpServer.hasPendingConnections() && !TcpServer.waitForNewConnection(1000) ) + { if (mStopped) { return; } } // block until a new connection is received + cout << "JackTrip HUB SERVER: Client Connection Received!" << endl; + + // Control loop to be able to exit if UDPs or TCPs error ocurr + for (int dum = 0; dum<1; dum++) { + QTcpSocket *clientConnection = TcpServer.nextPendingConnection(); + if ( !clientConnection->waitForConnected(tcpTimeout) ) { + std::cerr << clientConnection->errorString().toStdString() << endl; + break; + } + PeerAddress = clientConnection->peerAddress(); + cout << "JackTrip HUB SERVER: Client Connect Received from Address : " + << PeerAddress.toString().toStdString() << endl; + + // Get UDP port from client + // ------------------------ + peer_udp_port = readClientUdpPort(clientConnection); + if ( peer_udp_port == 0 ) { break; } + cout << "JackTrip HUB SERVER: Client UDP Port is = " << peer_udp_port << endl; + + // Check is client is new or not + // ----------------------------- + // Check if Address is not already in the thread pool + // check by comparing address strings (To handle IPv4 and IPv6.) + int id = isNewAddress(PeerAddress.toString(), peer_udp_port); + // If the address is not new, we need to remove the client from the pool + // before re-starting the connection + + if (id == -1) { + int id_remove; + id_remove = getPoolID(PeerAddress.toString(), peer_udp_port); + // stop the thread + mJTWorkers->at(id_remove)->stopThread(); + // block until the thread has been removed from the pool + while ( isNewAddress(PeerAddress.toString(), peer_udp_port) == -1 ) { + cout << "JackTrip HUB SERVER: Removing JackTripWorker from pool..." << endl; + QThread::msleep(10); + } + // Get a new ID for this client + //id = isNewAddress(PeerAddress.toIPv4Address(), peer_udp_port); + id = getPoolID(PeerAddress.toString(), peer_udp_port); + } + // Assign server port and send it to Client + server_udp_port = mBasePort+id; + if ( sendUdpPort(clientConnection, server_udp_port) == 0 ) { + clientConnection->close(); + delete clientConnection; + releaseThread(id); + break; + } + + // Close and Delete the socket + // --------------------------- + clientConnection->close(); + delete clientConnection; + cout << "JackTrip HUB SERVER: Client TCP Connection Closed!" << endl; + + // Spawn Thread to Pool + // -------------------- + // Register JackTripWorker with the master listener + delete mJTWorkers->at(id); // just in case the Worker was previously created + mJTWorkers->replace(id, new JackTripWorker(this, mBufferQueueLength, mUnderRunMode)); + // redirect port and spawn listener + cout << "JackTrip HUB SERVER: Spawning JackTripWorker..." << endl; + { + QMutexLocker lock(&mMutex); + mJTWorkers->at(id)->setJackTrip(id, + mActiveAddress[id].address, + server_udp_port, + mActiveAddress[id].port, + 1, + m_connectDefaultAudioPorts + ); /// \todo temp default to 1 channel + +// qDebug() << "mPeerAddress" << id << mActiveAddress[id].address << mActiveAddress[id].port; + } + //send one thread to the pool + cout << "JackTrip HUB SERVER: Starting JackTripWorker..." << endl; + mThreadPool.start(mJTWorkers->at(id), QThread::TimeCriticalPriority); + // wait until one is complete before another spawns + while (mJTWorkers->at(id)->isSpawning()) { QThread::msleep(10); } + //mTotalRunningThreads++; + cout << "JackTrip HUB SERVER: Total Running Threads: " << mTotalRunningThreads << endl; + cout << "===============================================================" << endl; + QThread::msleep(100); +#ifdef WAIR // WAIR + if (isWAIR()) connectMesh(true); // invoked with -Sw +#endif // endwhere + +// qDebug() << "mPeerAddress" << mActiveAddress[id].address << mActiveAddress[id].port; + + connectPatch(true); + } + } + + /* + // Create objects on the stack + QUdpSocket HubUdpSocket; + QHostAddress PeerAddress; + uint16_t peer_port; // Ougoing Peer port, in case they're not using the default + + // Bind the socket to the well known port + bindUdpSocket(HubUdpSocket, mServerPort); + + char buf[1]; + cout << "Server Listening in UDP Port: " << mServerPort << endl; + cout << "Waiting for client..." << endl; + cout << "=======================================================" << endl; + while ( !mStopped ) + { + //cout << "WAITING........................." << endl; + while ( HubUdpSocket.hasPendingDatagrams() ) + { + cout << "Received request from Client!" << endl; + // Get Client IP Address and outgoing port from packet + int rv = HubUdpSocket.readDatagram(buf, 1, &PeerAddress, &peer_port); + cout << "Peer Port in Server ==== " << peer_port << endl; + if (rv < 0) { std::cerr << "ERROR: Bad UDP packet read..." << endl; } + + /// \todo Get number of channels in the client from header + + // check by comparing 32-bit addresses + /// \todo Add the port number in the comparison + cout << "peer_portpeer_portpeer_port === " << peer_port << endl; + int id = isNewAddress(PeerAddress.toIPv4Address(), peer_port); + + //cout << "IDIDIDIDIDDID === " << id << endl; + + // If the address is new, create a new thread in the pool + if (id >= 0) // old address is -1 + { + // redirect port and spawn listener + sendToPoolPrototype(id); + // wait until one is complete before another spawns + while (mJTWorker->isSpawning()) { QThread::msleep(10); } + mTotalRunningThreads++; + cout << "Total Running Threads: " << mTotalRunningThreads << endl; + cout << "=======================================================" << endl; + } + //cout << "ENDDDDDDDDDDDDDDDDDd === " << id << endl; + } + QThread::msleep(100); + } + */ +} + + +//******************************************************************************* +// Returns 0 on error +int UdpHubListener::readClientUdpPort(QTcpSocket* clientConnection) +{ + // Read the size of the package + // ---------------------------- + //tcpClient.waitForReadyRead(); + cout << "JackTrip HUB SERVER: Reading UDP port from Client..." << endl; + while (clientConnection->bytesAvailable() < (int)sizeof(uint16_t)) { + if (!clientConnection->waitForReadyRead()) { + std::cerr << "TCP Socket ERROR: " << clientConnection->errorString().toStdString() << endl; + return 0; + } + } + + if (gVerboseFlag) cout << "Ready To Read From Client!" << endl; + // Read UDP Port Number from Server + // -------------------------------- + int udp_port; + int size = sizeof(udp_port); + char port_buf[size]; + clientConnection->read(port_buf, size); + std::memcpy(&udp_port, port_buf, size); + return udp_port; +} + + +//******************************************************************************* +int UdpHubListener::sendUdpPort(QTcpSocket* clientConnection, int udp_port) +{ + // Send Port Number to Client + // -------------------------- + char port_buf[sizeof(udp_port)]; + std::memcpy(port_buf, &udp_port, sizeof(udp_port)); + clientConnection->write(port_buf, sizeof(udp_port)); + while ( clientConnection->bytesToWrite() > 0 ) { + if ( clientConnection->state() == QAbstractSocket::ConnectedState ) { + clientConnection->waitForBytesWritten(-1); + } + else { + return 0; + } + } + return 1; + cout << "Port sent to Client" << endl; +} + + +//******************************************************************************* +/* +void UdpHubListener::sendToPoolPrototype(int id) +{ + mJTWorker->setJackTrip(id, mActiveAddress[id][0], + mBasePort+(2*id), mActiveAddress[id][1], + 1); /// \todo temp default to 1 channel + mThreadPool.start(mJTWorker, QThread::TimeCriticalPriority); //send one thread to the pool +} +*/ + + +//******************************************************************************* +void UdpHubListener::bindUdpSocket(QUdpSocket& udpsocket, int port) +{ + // QHostAddress::Any : let the kernel decide the active address + if ( !udpsocket.bind(QHostAddress::Any, + port, QUdpSocket::DefaultForPlatform) ) { + //std::cerr << "ERROR: could not bind UDP socket" << endl; + //std::exit(1); + throw std::runtime_error("Could not bind UDP socket. It may be already binded."); + } + else { + cout << "UDP Socket Receiving in Port: " << port << endl; + } +} + + +//******************************************************************************* +// check by comparing 32-bit addresses +int UdpHubListener::isNewAddress(QString address, uint16_t port) +{ + QMutexLocker lock(&mMutex); + bool busyAddress = false; + int id = 0; + + /* + while ( !busyAddress && (id 0 + return 0; /// \todo Check if we really need to return an argument here +} + +#ifdef WAIR // wair +#include "JMess.h" +//******************************************************************************* +void UdpHubListener::connectMesh(bool spawn) +{ + cout << ((spawn)?"spawning":"releasing") << " jacktripWorker so change mesh" << endl; + JMess tmp; + tmp.connectSpawnedPorts(gDefaultNumInChannels); // change gDefaultNumInChannels if more than stereo LAIR interconnects + // tmp.disconnectAll(); + // enumerateRunningThreadIDs(); +} + +//******************************************************************************* +void UdpHubListener::enumerateRunningThreadIDs() +{ + for (int id = 0; id +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "JackTrip.h" +#include "jacktrip_types.h" +#include "jacktrip_globals.h" +class JackTripWorker; // forward declaration +class Settings; + +typedef struct { + QString address; + int16_t port; +} addressPortPair; + +/** \brief Hub UDP listener on the Server. + * + * This creates a server that will listen on the well know port (the server port) and will + * spawn JackTrip threads into the Thread pool. Clients request a connection. + */ +class UdpHubListener : public QThread +{ + Q_OBJECT; + +public: + UdpHubListener(int server_port = gServerUdpPort); + virtual ~UdpHubListener(); + + /// \brief Implements the Thread Loop. To start the thread, call start() + /// ( DO NOT CALL run() ) + void run(); + + /// \brief Stops the execution of the Thread + void stop() { mStopped = true; } + + int releaseThread(int id); + + void setConnectDefaultAudioPorts(bool connectDefaultAudioPorts) { m_connectDefaultAudioPorts = connectDefaultAudioPorts; } + + void setSettings(Settings* s) {m_settings = s;} + Settings* getSettings() const {return m_settings;} + +private slots: + void testReceive() + { std::cout << "========= TEST RECEIVE SLOT ===========" << std::endl; } + +signals: + void Listening(); + void ClientAddressSet(); + void signalRemoveThread(int id); + + +private: + /** \brief Binds a QUdpSocket. It chooses the available (active) interface. + * \param udpsocket a QUdpSocket + * \param port Port number + */ + static void bindUdpSocket(QUdpSocket& udpsocket, int port); + + int readClientUdpPort(QTcpSocket* clientConnection); + int sendUdpPort(QTcpSocket* clientConnection, int udp_port); + + + /** \brief Send the JackTripWorker to the thread pool. This will run + * until it's done. We still have control over the prototype class. + * \param id Identification Number + */ + //void sendToPoolPrototype(int id); + + /** \brief Check if address is already handled, if not add to array + * \param address as string (IPv4 or IPv6) + * \return -1 if address is busy, id number if not + */ + int isNewAddress(QString address, uint16_t port); + + /** \brief Returns the ID of the client in the pool. If the client + * is not in the pool yet, returns -1. + */ + int getPoolID(QString address, uint16_t port); + + //QUdpSocket mUdpHubSocket; ///< The UDP socket + //QHostAddress mPeerAddress; ///< The Peer Address + + //JackTripWorker* mJTWorker; ///< Class that will be used as prototype + QVector* mJTWorkers; ///< Vector of JackTripWorker s + QThreadPool mThreadPool; ///< The Thread Pool + + int mServerPort; //< Server known port number + int mBasePort; + addressPortPair mActiveAddress[gMaxThreads]; ///< Active address pool addresses + QHash mActiveAddressPortPair; + + /// Boolean stop the execution of the thread + volatile bool mStopped; + int mTotalRunningThreads; ///< Number of Threads running in the pool + QMutex mMutex; + JackTrip::underrunModeT mUnderRunMode; + int mBufferQueueLength; + + bool m_connectDefaultAudioPorts; + Settings* m_settings; + +#ifdef WAIR // wair + bool mWAIR; + void connectMesh(bool spawn); + void enumerateRunningThreadIDs(); +public : + void setWAIR(int b) {mWAIR = b;} + bool isWAIR() {return mWAIR;} +#endif // endwhere + void connectPatch(bool spawn); +public : + unsigned int mHubPatch; + void setHubPatch(unsigned int p) {mHubPatch = p;} + unsigned int getHubPatch() {return mHubPatch;} + + void setUnderRunMode(JackTrip::underrunModeT UnderRunMode) { mUnderRunMode = UnderRunMode; } + void setBufferQueueLength(int BufferQueueLength) { mBufferQueueLength = BufferQueueLength; } +}; + + +#endif //__UDPHUBLISTENER_H__ diff --git a/src/UdpMasterListener.cpp b/src/UdpMasterListener.cpp deleted file mode 100644 index 3c17676..0000000 --- a/src/UdpMasterListener.cpp +++ /dev/null @@ -1,474 +0,0 @@ -//***************************************************************** -/* - JackTrip: A System for High-Quality Audio Network Performance - over the Internet - - Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe. - SoundWIRE group at CCRMA, Stanford University. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. -*/ -//***************************************************************** - -/** - * \file UdpMasterListener.cpp - * \author Juan-Pablo Caceres and Chris Chafe - * \date September 2008 - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "UdpMasterListener.h" -#include "JackTripWorker.h" -#include "jacktrip_globals.h" - -using std::cout; using std::endl; - - -//******************************************************************************* -UdpMasterListener::UdpMasterListener(int server_port) : - //mJTWorker(NULL), - mServerPort(server_port), - mStopped(false), - #ifdef WAIR // wair - mWAIR(false), - #endif // endwhere - mTotalRunningThreads(0), - m_connectDefaultAudioPorts(false) -{ - // Register JackTripWorker with the master listener - //mJTWorker = new JackTripWorker(this); - mJTWorkers = new QVector; - for (int i = 0; iinsert(i, NULL); - } - - - //mJTWorkers = new JackTripWorker(this); - mThreadPool.setExpiryTimeout(3000); // msec (-1) = forever - // Inizialize IP addresses - for (int i = 0; iat(i); - } - delete mJTWorkers; -} - - -//******************************************************************************* -// Now that the first handshake is with TCP server, if the addreess/peer port of -// the client is already on the thread pool, it means that a new connection is -// requested (the old was desconnected). So we have to remove that thread from -// the pool and then connect again. -void UdpMasterListener::run() -{ - mStopped = false; - - QHostAddress PeerAddress; // Object to store peer address - int peer_udp_port; // Peer listening port - int server_udp_port; // Server assigned udp port - - // Create and bind the TCP server - // ------------------------------ - QTcpServer TcpServer; - if ( !TcpServer.listen(QHostAddress::Any, mServerPort) ) { - std::cerr << "TCP Socket Server ERROR: " << TcpServer.errorString().toStdString() << endl; - std::exit(1); - } - - const int tcpTimeout = 5*1000; - - - cout << "JackTrip HUB SERVER: TCP Server Listening in Port = " << TcpServer.serverPort() << endl; - while ( !mStopped ) - { - cout << "JackTrip HUB SERVER: Waiting for client connections..." << endl; - cout << "JackTrip HUB SERVER: Hub auto audio patch setting = " << mHubPatch << endl; - cout << "=======================================================" << endl; - while ( !TcpServer.waitForNewConnection(1000) ) - { if (mStopped) { return; } } // block until a new connection is received - cout << "JackTrip HUB SERVER: Client Connection Received!" << endl; - - // Control loop to be able to exit if UDPs or TCPs error ocurr - for (int dum = 0; dum<1; dum++) { - QTcpSocket *clientConnection = TcpServer.nextPendingConnection(); - if ( !clientConnection->waitForConnected(tcpTimeout) ) { - std::cerr << clientConnection->errorString().toStdString() << endl; - break; - } - PeerAddress = clientConnection->peerAddress(); - cout << "JackTrip HUB SERVER: Client Connect Received from Address : " - << PeerAddress.toString().toStdString() << endl; - - // Get UDP port from client - // ------------------------ - peer_udp_port = readClientUdpPort(clientConnection); - if ( peer_udp_port == 0 ) { break; } - cout << "JackTrip HUB SERVER: Client UDP Port is = " << peer_udp_port << endl; - - // Check is client is new or not - // ----------------------------- - // Check if Address is not already in the thread pool - // check by comparing address strings (To handle IPv4 and IPv6.) - int id = isNewAddress(PeerAddress.toString(), peer_udp_port); - // If the address is not new, we need to remove the client from the pool - // before re-starting the connection - - if (id == -1) { - int id_remove; - id_remove = getPoolID(PeerAddress.toString(), peer_udp_port); - // stop the thread - mJTWorkers->at(id_remove)->stopThread(); - // block until the thread has been removed from the pool - while ( isNewAddress(PeerAddress.toString(), peer_udp_port) == -1 ) { - cout << "JackTrip HUB SERVER: Removing JackTripWorker from pool..." << endl; - QThread::msleep(10); - } - // Get a new ID for this client - //id = isNewAddress(PeerAddress.toIPv4Address(), peer_udp_port); - id = getPoolID(PeerAddress.toString(), peer_udp_port); - } - // Assign server port and send it to Client - server_udp_port = mBasePort+id; - if ( sendUdpPort(clientConnection, server_udp_port) == 0 ) { - clientConnection->close(); - delete clientConnection; - releaseThread(id); - break; - } - - // Close and Delete the socket - // --------------------------- - clientConnection->close(); - delete clientConnection; - cout << "JackTrip HUB SERVER: Client TCP Connection Closed!" << endl; - - // Spawn Thread to Pool - // -------------------- - // Register JackTripWorker with the master listener - delete mJTWorkers->at(id); // just in case the Worker was previously created - mJTWorkers->replace(id, new JackTripWorker(this, mBufferQueueLength, mUnderRunMode)); - // redirect port and spawn listener - cout << "JackTrip HUB SERVER: Spawning JackTripWorker..." << endl; - { - QMutexLocker lock(&mMutex); - mJTWorkers->at(id)->setJackTrip(id, - mActiveAddress[id].address, - server_udp_port, - mActiveAddress[id].port, - 1, - m_connectDefaultAudioPorts - ); /// \todo temp default to 1 channel - - qDebug() << "mPeerAddress" << id << mActiveAddress[id].address << mActiveAddress[id].port; - } - //send one thread to the pool - cout << "JackTrip HUB SERVER: Starting JackTripWorker..." << endl; - mThreadPool.start(mJTWorkers->at(id), QThread::TimeCriticalPriority); - // wait until one is complete before another spawns - while (mJTWorkers->at(id)->isSpawning()) { QThread::msleep(10); } - //mTotalRunningThreads++; - cout << "JackTrip HUB SERVER: Total Running Threads: " << mTotalRunningThreads << endl; - cout << "===============================================================" << endl; - QThread::msleep(100); -#ifdef WAIR // WAIR - if (isWAIR()) connectMesh(true); // invoked with -Sw -#endif // endwhere - - qDebug() << "mPeerAddress" << mActiveAddress[id].address << mActiveAddress[id].port; - - connectPatch(true); - } - } - - /* - // Create objects on the stack - QUdpSocket MasterUdpSocket; - QHostAddress PeerAddress; - uint16_t peer_port; // Ougoing Peer port, in case they're not using the default - - // Bind the socket to the well known port - bindUdpSocket(MasterUdpSocket, mServerPort); - - char buf[1]; - cout << "Server Listening in UDP Port: " << mServerPort << endl; - cout << "Waiting for client..." << endl; - cout << "=======================================================" << endl; - while ( !mStopped ) - { - //cout << "WAITING........................." << endl; - while ( MasterUdpSocket.hasPendingDatagrams() ) - { - cout << "Received request from Client!" << endl; - // Get Client IP Address and outgoing port from packet - int rv = MasterUdpSocket.readDatagram(buf, 1, &PeerAddress, &peer_port); - cout << "Peer Port in Server ==== " << peer_port << endl; - if (rv < 0) { std::cerr << "ERROR: Bad UDP packet read..." << endl; } - - /// \todo Get number of channels in the client from header - - // check by comparing 32-bit addresses - /// \todo Add the port number in the comparison - cout << "peer_portpeer_portpeer_port === " << peer_port << endl; - int id = isNewAddress(PeerAddress.toIPv4Address(), peer_port); - - //cout << "IDIDIDIDIDDID === " << id << endl; - - // If the address is new, create a new thread in the pool - if (id >= 0) // old address is -1 - { - // redirect port and spawn listener - sendToPoolPrototype(id); - // wait until one is complete before another spawns - while (mJTWorker->isSpawning()) { QThread::msleep(10); } - mTotalRunningThreads++; - cout << "Total Running Threads: " << mTotalRunningThreads << endl; - cout << "=======================================================" << endl; - } - //cout << "ENDDDDDDDDDDDDDDDDDd === " << id << endl; - } - QThread::msleep(100); - } - */ -} - - -//******************************************************************************* -// Returns 0 on error -int UdpMasterListener::readClientUdpPort(QTcpSocket* clientConnection) -{ - // Read the size of the package - // ---------------------------- - //tcpClient.waitForReadyRead(); - cout << "JackTrip HUB SERVER: Reading UDP port from Client..." << endl; - while (clientConnection->bytesAvailable() < (int)sizeof(uint16_t)) { - if (!clientConnection->waitForReadyRead()) { - std::cerr << "TCP Socket ERROR: " << clientConnection->errorString().toStdString() << endl; - return 0; - } - } - - if (gVerboseFlag) cout << "Ready To Read From Client!" << endl; - // Read UDP Port Number from Server - // -------------------------------- - int udp_port; - int size = sizeof(udp_port); - char port_buf[size]; - clientConnection->read(port_buf, size); - std::memcpy(&udp_port, port_buf, size); - return udp_port; -} - - -//******************************************************************************* -int UdpMasterListener::sendUdpPort(QTcpSocket* clientConnection, int udp_port) -{ - // Send Port Number to Client - // -------------------------- - char port_buf[sizeof(udp_port)]; - std::memcpy(port_buf, &udp_port, sizeof(udp_port)); - clientConnection->write(port_buf, sizeof(udp_port)); - while ( clientConnection->bytesToWrite() > 0 ) { - if ( clientConnection->state() == QAbstractSocket::ConnectedState ) { - clientConnection->waitForBytesWritten(-1); - } - else { - return 0; - } - } - return 1; - cout << "Port sent to Client" << endl; -} - - -//******************************************************************************* -/* -void UdpMasterListener::sendToPoolPrototype(int id) -{ - mJTWorker->setJackTrip(id, mActiveAddress[id][0], - mBasePort+(2*id), mActiveAddress[id][1], - 1); /// \todo temp default to 1 channel - mThreadPool.start(mJTWorker, QThread::TimeCriticalPriority); //send one thread to the pool -} -*/ - - -//******************************************************************************* -void UdpMasterListener::bindUdpSocket(QUdpSocket& udpsocket, int port) throw(std::runtime_error) -{ - // QHostAddress::Any : let the kernel decide the active address - if ( !udpsocket.bind(QHostAddress::Any, - port, QUdpSocket::DefaultForPlatform) ) { - //std::cerr << "ERROR: could not bind UDP socket" << endl; - //std::exit(1); - throw std::runtime_error("Could not bind UDP socket. It may be already binded."); - } - else { - cout << "UDP Socket Receiving in Port: " << port << endl; - } -} - - -//******************************************************************************* -// check by comparing 32-bit addresses -int UdpMasterListener::isNewAddress(QString address, uint16_t port) -{ - QMutexLocker lock(&mMutex); - bool busyAddress = false; - int id = 0; - - /* - while ( !busyAddress && (id 0 - return 0; /// \todo Check if we really need to return an argument here -} - -#ifdef WAIR // wair -#include "JMess.h" -//******************************************************************************* -void UdpMasterListener::connectMesh(bool spawn) -{ - cout << ((spawn)?"spawning":"releasing") << " jacktripWorker so change mesh" << endl; - JMess tmp; - tmp.connectSpawnedPorts(gDefaultNumInChannels); // change gDefaultNumInChannels if more than stereo LAIR interconnects - // tmp.disconnectAll(); - // enumerateRunningThreadIDs(); -} - -//******************************************************************************* -void UdpMasterListener::enumerateRunningThreadIDs() -{ - for (int id = 0; id -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "JackTrip.h" -#include "jacktrip_types.h" -#include "jacktrip_globals.h" -class JackTripWorker; // forward declaration - -typedef struct { - QString address; - int16_t port; -} addressPortPair; - -/** \brief Master UDP listener on the Server. - * - * This creates a server that will listen on the well know port (the server port) and will - * spawn JackTrip threads into the Thread pool. Clients request a connection. - */ -class UdpMasterListener : public QThread -{ - Q_OBJECT; - -public: - UdpMasterListener(int server_port = gServerUdpPort); - virtual ~UdpMasterListener(); - - /// \brief Implements the Thread Loop. To start the thread, call start() - /// ( DO NOT CALL run() ) - void run(); - - /// \brief Stops the execution of the Thread - void stop() { mStopped = true; } - - int releaseThread(int id); - - void setConnectDefaultAudioPorts(bool connectDefaultAudioPorts) { m_connectDefaultAudioPorts = connectDefaultAudioPorts; } - -private slots: - void testReceive() - { std::cout << "========= TEST RECEIVE SLOT ===========" << std::endl; } - -signals: - void Listening(); - void ClientAddressSet(); - void signalRemoveThread(int id); - - -private: - /** \brief Binds a QUdpSocket. It chooses the available (active) interface. - * \param udpsocket a QUdpSocket - * \param port Port number - */ - static void bindUdpSocket(QUdpSocket& udpsocket, int port) throw(std::runtime_error); - - int readClientUdpPort(QTcpSocket* clientConnection); - int sendUdpPort(QTcpSocket* clientConnection, int udp_port); - - - /** \brief Send the JackTripWorker to the thread pool. This will run - * until it's done. We still have control over the prototype class. - * \param id Identification Number - */ - //void sendToPoolPrototype(int id); - - /** \brief Check if address is already handled, if not add to array - * \param address as string (IPv4 or IPv6) - * \return -1 if address is busy, id number if not - */ - int isNewAddress(QString address, uint16_t port); - - /** \brief Returns the ID of the client in the pool. If the client - * is not in the pool yet, returns -1. - */ - int getPoolID(QString address, uint16_t port); - - //QUdpSocket mUdpMasterSocket; ///< The UDP socket - //QHostAddress mPeerAddress; ///< The Peer Address - - //JackTripWorker* mJTWorker; ///< Class that will be used as prototype - QVector* mJTWorkers; ///< Vector of JackTripWorker s - QThreadPool mThreadPool; ///< The Thread Pool - - int mServerPort; //< Server known port number - int mBasePort; - addressPortPair mActiveAddress[gMaxThreads]; ///< Active address pool addresses - QHash mActiveAddressPortPair; - - /// Boolean stop the execution of the thread - volatile bool mStopped; - int mTotalRunningThreads; ///< Number of Threads running in the pool - QMutex mMutex; - JackTrip::underrunModeT mUnderRunMode; - int mBufferQueueLength; - - bool m_connectDefaultAudioPorts; - -#ifdef WAIR // wair - bool mWAIR; - void connectMesh(bool spawn); - void enumerateRunningThreadIDs(); -public : - void setWAIR(int b) {mWAIR = b;} - bool isWAIR() {return mWAIR;} -#endif // endwhere - void connectPatch(bool spawn); -public : - unsigned int mHubPatch; - void setHubPatch(unsigned int p) {mHubPatch = p;} - unsigned int getHubPatch() {return mHubPatch;} - - void setUnderRunMode(JackTrip::underrunModeT UnderRunMode) { mUnderRunMode = UnderRunMode; } - void setBufferQueueLength(int BufferQueueLength) { mBufferQueueLength = BufferQueueLength; } -}; - - -#endif //__UDPMASTERLISTENER_H__ diff --git a/src/build b/src/build index 15011b4..e3f7150 100755 --- a/src/build +++ b/src/build @@ -17,9 +17,6 @@ if [[ $platform == 'linux' ]]; then if hash qmake-qt5 2>/dev/null; then echo "Using qmake-qt5" QCMD=qmake-qt5 - elif hash qmake-qt4 2>/dev/null; then - echo "Using qmake-qt4" - QCMD=qmake-qt4 elif hash qmake 2>/dev/null; then #in case qt was compiled by user echo "Using qmake" QCMD=qmake @@ -31,15 +28,17 @@ elif [[ $platform == 'macosx' ]]; then fi # Build +mkdir -p ../builddir +cd ../builddir if [[ $1 == 'nojack' ]]; then echo "Building without Jack" - $QCMD -spec $QSPEC -config nojack jacktrip.pro + $QCMD -spec $QSPEC -config nojack ../src/jacktrip.pro make clean - $QCMD -spec $QSPEC -config nojack jacktrip.pro + $QCMD -spec $QSPEC -config nojack ../src/jacktrip.pro make release else - $QCMD -spec $QSPEC jacktrip.pro + $QCMD -spec $QSPEC ../src/jacktrip.pro make clean - $QCMD -spec $QSPEC jacktrip.pro + $QCMD -spec $QSPEC ../src/jacktrip.pro make release fi diff --git a/src/jacktrip.pro b/src/jacktrip.pro index 590419f..f898c63 100644 --- a/src/jacktrip.pro +++ b/src/jacktrip.pro @@ -15,9 +15,9 @@ CONFIG(debug, debug|release) { QT -= gui QT += network -# rc.1.2 switch enables experimental wair build, merge some of it with WAIRTOMASTER +# rc.1.2 switch enables experimental wair build, merge some of it with WAIRTOHUB # DEFINES += WAIR -DEFINES += WAIRTOMASTER +DEFINES += WAIRTOHUB # http://wiki.qtcentre.org/index.php?title=Undocumented_qmake#Custom_tools #cc DEFINES += __RT_AUDIO__ @@ -135,7 +135,7 @@ HEADERS += DataProtocol.h \ TestRingBuffer.h \ ThreadPoolTest.h \ UdpDataProtocol.h \ - UdpMasterListener.h \ + UdpHubListener.h \ AudioInterface.h !nojack { @@ -155,7 +155,7 @@ SOURCES += DataProtocol.cpp \ RingBuffer.cpp \ Settings.cpp \ UdpDataProtocol.cpp \ - UdpMasterListener.cpp \ + UdpHubListener.cpp \ AudioInterface.cpp !nojack { diff --git a/src/jacktrip_globals.h b/src/jacktrip_globals.h index 9f31e6a..e0dfa08 100644 --- a/src/jacktrip_globals.h +++ b/src/jacktrip_globals.h @@ -44,7 +44,7 @@ /// \todo Add this namespace //namespace JackTrip -const char* const gVersion = "1.2beta2"; ///< JackTrip version +const char* const gVersion = "1.2.1"; ///< JackTrip version //******************************************************************************* /// \name Default Values @@ -55,7 +55,8 @@ const int gDefaultNumOutChannels = 2; #define PROTOCOL_STACK QHostAddress::AnyIPv4 // as opposed to Any // #define WAIR_AUDIO_NAME "JackTrip" // for jack connection const QString WAIR_AUDIO_NAME = QString("JackTrip"); // keep legacy for WAIR -const int gMAX_WAIRS = 10; // jmess revision needed for string parse if > 1 digit +const int gMAX_WAIRS = 128; // FIXME, should agree with maxThreadCount +// jmess revision needed for string parse if > 1 digit // hubpatch = 3 for TUB ensemble patching /////////////////////////////// @@ -89,7 +90,7 @@ const uint32_t gDefaultDeviceID = 0; const uint32_t gDefaultBufferSizeInSamples = 128; const QString gDefaultLocalAddress = QString(); const int gDefaultRedundancy = 1; -const int gTimeOutMultiThreadedServer = 5000; // seconds +const int gTimeOutMultiThreadedServer = 10000; // seconds const int gWaitCounter = 60; //@} @@ -122,6 +123,7 @@ extern int gVerboseFlag; ///< Verbose mode flag declaration /// \name JackAudio //@{ const int gJackBitResolution = 32; ///< Audio Bit Resolution of the Jack Server +const char* const gJackDefaultClientName = "JackTrip"; //@} @@ -135,7 +137,7 @@ void setRealtimeProcessPriority(); /// \name JackTrip Server parameters //@{ /// Maximum Threads that can be run at the same time -const int gMaxThreads = 290; // some pthread limit around 297? +const int gMaxThreads = 1024; /// Public well-known UDP port to where the clients will connect const int gServerUdpPort = 4464;