New upstream version 1.2.1+ds0
authorDennis Braun <d_braun@kabelmail.de>
Wed, 12 Aug 2020 14:40:55 +0000 (16:40 +0200)
committerDennis Braun <d_braun@kabelmail.de>
Wed, 12 Aug 2020 14:40:55 +0000 (16:40 +0200)
28 files changed:
.gitignore
.travis.yml [new file with mode: 0644]
CHANGESLOG.txt
INSTALL.txt
INSTALL_meson.md [new file with mode: 0644]
JMess.cpp
README.md
meson.build [new file with mode: 0644]
src/DataProtocol.h
src/JMess.cpp
src/JMess.h
src/JackTrip.cpp
src/JackTrip.h
src/JackTripWorker.cpp
src/JackTripWorker.h
src/RingBuffer.cpp
src/RingBuffer.h
src/Settings.cpp
src/Settings.h
src/UdpDataProtocol.cpp
src/UdpDataProtocol.h
src/UdpHubListener.cpp [new file with mode: 0644]
src/UdpHubListener.h [new file with mode: 0644]
src/UdpMasterListener.cpp [deleted file]
src/UdpMasterListener.h [deleted file]
src/build
src/jacktrip.pro
src/jacktrip_globals.h

index 1afe92a22e65a0a64d39e3b5c369e7643f6fda78..c9dcabe21ec593a2da0632f6eebd11f8024be623 100644 (file)
@@ -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 (file)
index 0000000..f551d99
--- /dev/null
@@ -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 :("
index c8dc135c22f88cb42382b0495ee5411c45971296..3377943fdc77507801027354d771025d410e8dd5 100644 (file)
@@ -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)
index 2ca162487e7ce195d298a9ebb689fc6c5c227469..f8b23dc59f15c1c269bfc54b446488a3e4d95974 100644 (file)
@@ -103,7 +103,7 @@ $ qmake -config nojack jacktrip.pro
 $ make release\r
 \r
 \r
-If you want to install (using Terminal): on the /src directory type:\r
+If you want to install (using Terminal): on the /builddir directory type:\r
 \r
 $ sudo cp jacktrip /usr/local/bin/\r
   (enter your password when prompted)\r
diff --git a/INSTALL_meson.md b/INSTALL_meson.md
new file mode 100644 (file)
index 0000000..fda5b39
--- /dev/null
@@ -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
index 30b20dc7fa255be9e416188e244bf7b7aed2a99b..2708bc4583ec917063914debed6bc35c160f9988 100644 (file)
--- 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
index 94906161e9bcdadf724d1a46331ae1440cd0b3ef..201635edb58ae902d2f284fb9739461fda6dbd7f 100644 (file)
--- 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 (file)
index 0000000..6debd45
--- /dev/null
@@ -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 )
index 816e6a826141f38566761586c22e3ee44ff770c9..413263d12e43be4fbbd86929134be48cd4df772a 100644 (file)
@@ -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);
index b49008c652d53fe6943dd0965333d13762e0ac23..8cdab74d50aa31510553b835447729a1a2a45936 100644 (file)
@@ -35,6 +35,8 @@
 #include "jacktrip_globals.h"
 #include <QDebug>
 
+// 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<ctr; i++) qDebug() << IPS[i];
+//    for (int i = 0; i<ctr; i++) qDebug() << IPS[i];
     disconnectAll();
 
     int k = 0;
@@ -212,8 +217,8 @@ void JMess::connectSpawnedPorts(int nChans, int hubPatch)
             if ((hubPatch == JackTrip::CLIENTECHO)||(hubPatch == JackTrip::FULLMIX)) k = i;
             else if (hubPatch == JackTrip::CLIENTFOFI) k = (j+(i+1))%ctr;
             for (int l = 1; l<=nChans; l++) { // chans are 1-based
-                qDebug() << "connect " << IPS[i]+":receive_"+QString::number(l)
-                         <<"with " << IPS[k]+":send_"+QString::number(l);
+//                qDebug() << "connect " << IPS[i]+":receive_"+QString::number(l)
+//                         <<"with " << IPS[k]+":send_"+QString::number(l);
 
                 QString left = IPS[i] +
                         ":receive_" + QString::number(l);
@@ -239,8 +244,8 @@ void JMess::connectSpawnedPorts(int nChans, int hubPatch)
             for (int j = 0; j<jLimit; j++) {
                 k = (j+(i+1))%ctr;
                 for (int l = 1; l<=nChans; l++) { // chans are 1-based
-                    qDebug() << "connect " << IPS[i]+":receive_"+QString::number(l)
-                             <<"with " << IPS[k]+":send_"+QString::number(l);
+//                    qDebug() << "connect " << IPS[i]+":receive_"+QString::number(l)
+//                             <<"with " << IPS[k]+":send_"+QString::number(l);
 
                     QString left = IPS[i] +
                             ":receive_" + QString::number(l);
@@ -307,7 +312,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
index 48d5b440a418071d87fdfc5479eef9e22840659c..3096ceff5e0e73f60be3e0cd1170f220571b50e9 100644 (file)
@@ -44,6 +44,7 @@
 //#include <QXmlSimpleReader>
 //#include <QXmlInputSource>
 //#include <QXmlContentHandler>
+#include <QMutexLocker>
 
 #include <jack/jack.h>
 
@@ -87,5 +88,6 @@ private:
   //OuputPortN InputPortN
   QVector<QVector<QString> > mConnectedPorts;
   QVector<QVector<QString> > mPortsToConnect;
+  static QMutex sJMessMutex; ///< Mutex to make thread safe jack functions that are not
 };
 #endif
index 85d91cdc2c1f32fe73783b4af24f1906e61cba78..c425851d9a8286341cdb229474abc87623c7d836 100644 (file)
@@ -52,6 +52,8 @@
 #include <QHostInfo>
 #include <QThread>
 #include <QTcpSocket>
+#include <QTimer>
+#include <QDateTime>
 
 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;
index aa00a2c0363577adc4d969fb06dd961dd7ff2ce5..594e22abfff97acbc05c370d26264b3d2b4ecdb3 100644 (file)
@@ -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
index 84b825fabbead2f7281dc3eedafbc2f59ad9e9df..f00626118d6976698432775afd6ff1176c6f9e9b 100644 (file)
 
 #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;
index 06760e560a38b893b64b3b180fa293fa9ebb599c..62c65dae8b0ad25b8496226f67f58d1ecbab033c 100644 (file)
@@ -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
index 5b951619790de7c58b58f9afa974911e2a6ac76e..124399ed902ec307d52317820fa37746d8ce60a6 100644 (file)
@@ -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;
+}
index 5da8208639dc036199d8255c7d5e924f15d14cba..78e137f79c2d1b0bfb55bfe2caef21835e0b6b83 100644 (file)
@@ -44,6 +44,8 @@
 
 #include "jacktrip_types.h"
 
+#include <atomic>
+
 //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<uint32_t> mUnderruns;
+    std::atomic<uint32_t> mOverflows;
 };
 
 #endif
index 25caf4710183ad2aeb076859a8f3845587bb02a9..541ee8aa995e7b5846c1f6167e7ecaa6a0fae2ec 100644 (file)
@@ -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 <time_in_secs>                Turn on IO stat reporting with specified interval (in seconds)" << endl;
+    cout << "   --iostatlog <log_file>                 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();
index 9272755e62149acd601e4d3c2ddd9cc872abbb96..dba212ed6150dca907e16ce737a9440301c8bd5d 100644 (file)
@@ -40,6 +40,7 @@
 #define __SETTINGS_H__
 
 #include <cstdlib>
+#include <fstream>
 
 #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
index b08ae9eea54491b6e11ad1f3c3bfc783356c4d25..85738a6dc6934325778820b37bff5f04d2f2cd98 100644 (file)
@@ -51,7 +51,7 @@
 #include <winsock2.h> //cc need SD_SEND
 #include <ws2tcpip.h> // for IPv6
 #endif
-#if defined (__LINUX__) || (__MAC__OSX__)
+#if defined (__LINUX__) || (__MAC_OSX__)
 #include <sys/socket.h> // 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,
index 2d09fe3f37b64bb5b765fedfd19d57ad354f5c83..13d58f9535aa1af48225903bc9b8ec8ad57fb601 100644 (file)
@@ -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<uint32_t>  mTotCount;
+    std::atomic<uint32_t>  mLostCount;
+    std::atomic<uint32_t>  mOutOfOrderCount;
+    std::atomic<uint32_t>  mRevivedCount;
+    uint32_t  mStatCount;
 };
 
 #endif // __UDPDATAPROTOCOL_H__
diff --git a/src/UdpHubListener.cpp b/src/UdpHubListener.cpp
new file mode 100644 (file)
index 0000000..b69b7b1
--- /dev/null
@@ -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 <iostream>
+#include <cstdlib>
+#include <stdexcept>
+#include <cstring>
+
+#include <QTcpServer>
+#include <QTcpSocket>
+#include <QStringList>
+#include <QMutexLocker>
+
+#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<JackTripWorker*>;
+    for (int i = 0; i<gMaxThreads; i++) {
+        mJTWorkers->insert(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; i<gMaxThreads; i++) {
+        mActiveAddress[i].address = ""; // Address strings
+        mActiveAddress[i].port = 0;
+    }
+    // Set the base dynamic port
+    // The Dynamic and/or Private Ports are those from 49152 through 65535
+    // mBasePort = ( rand() % ( (65535 - gMaxThreads) - 49152 ) ) + 49152;
+
+    // SoundWIRE ports open are UDP 61000-62000
+    mBasePort = 61000;
+
+    mUnderRunMode = JackTrip::WAVETABLE;
+    mBufferQueueLength = gDefaultQueueLength;
+}
+
+
+//*******************************************************************************
+UdpHubListener::~UdpHubListener()
+{
+    QMutexLocker lock(&mMutex);
+    mThreadPool.waitForDone();
+    //delete mJTWorker;
+    for (int i = 0; i<gMaxThreads; i++) {
+        delete mJTWorkers->at(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<mThreadPool.activeThreadCount()) )
+  {
+    if ( address==mActiveAddress[id][0] &&  port==mActiveAddress[id][1]) { busyAddress = true; }
+    id++;
+  }
+  */
+    for (int i = 0; i<gMaxThreads; i++) {
+        if ( address==mActiveAddress[i].address &&  port==mActiveAddress[i].port) {
+            id = i;
+            busyAddress = true;
+        }
+    }
+    if ( !busyAddress ) {
+        /*
+    mActiveAddress[id][0] = address;
+    mActiveAddress[id][1] = port;
+  } else {
+  */
+        id = 0;
+        bool foundEmptyAddress = false;
+        while ( !foundEmptyAddress && (id<gMaxThreads) ) {
+            if ( mActiveAddress[id].address.isEmpty() &&  (mActiveAddress[id].port == 0) ) {
+                foundEmptyAddress = true;
+                mActiveAddress[id].address = address;
+                mActiveAddress[id].port = port;
+            }  else {
+                id++;
+            }
+        }
+    }
+    if (!busyAddress) {
+        mTotalRunningThreads++;
+    }
+    return ((busyAddress) ? -1 : id);
+}
+
+
+//*******************************************************************************
+int UdpHubListener::getPoolID(QString address, uint16_t port)
+{
+    QMutexLocker lock(&mMutex);
+    //for (int id = 0; id<mThreadPool.activeThreadCount(); id++ )
+    for (int id = 0; id<gMaxThreads; id++ )
+    {
+        if ( address==mActiveAddress[id].address &&  port==mActiveAddress[id].port)
+        { return id; }
+    }
+    return -1;
+}
+
+
+//*******************************************************************************
+int UdpHubListener::releaseThread(int id)
+{
+    QMutexLocker lock(&mMutex);
+    mActiveAddress[id].address = "";
+    mActiveAddress[id].port = 0;
+    mTotalRunningThreads--;
+#ifdef WAIR // wair
+    if (isWAIR()) connectMesh(false); // invoked with -Sw
+#endif // endwhere
+    if (getHubPatch()) connectPatch(false); // invoked with -p > 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<gMaxThreads; id++ )
+    {
+        if ( !mActiveAddress[id].address.isEmpty() )
+        { qDebug() << id; }
+    }
+}
+#endif // endwhere
+
+#include "JMess.h"
+void UdpHubListener::connectPatch(bool spawn)
+{
+    if(m_connectDefaultAudioPorts) {
+      cout << ((spawn)?"spawning":"releasing") << " jacktripWorker so change patch" << endl;
+    } else {
+      cout << ((spawn)?"spawning":"releasing") << " jacktripWorker" << endl;
+    }
+    JMess tmp;
+    // default is patch 0, which connects server audio to all clients
+    // these are the other cases:
+    if (getHubPatch() == JackTrip::RESERVEDMATRIX) // special patch for TU Berlin ensemble
+        tmp.connectTUB(gDefaultNumInChannels);
+    else if ((getHubPatch() == JackTrip::CLIENTECHO) || // client loopback for testing
+             (getHubPatch() == JackTrip::CLIENTFOFI) || // all clients to all clients except self
+             (getHubPatch() == JackTrip::FULLMIX)) // all clients to all clients including self
+        tmp.connectSpawnedPorts(gDefaultNumInChannels,getHubPatch());
+    // FIXME: need change to gDefaultNumInChannels if more than stereo
+}
+
+// TODO:
+// USE bool QAbstractSocket::isValid () const to check if socket is connect. if not, exit loop
diff --git a/src/UdpHubListener.h b/src/UdpHubListener.h
new file mode 100644 (file)
index 0000000..82dca3b
--- /dev/null
@@ -0,0 +1,169 @@
+//*****************************************************************
+/*
+  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.h
+ * \author Juan-Pablo Caceres and Chris Chafe
+ * \date September 2008
+ */
+
+#ifndef __UDPHUBLISTENER_H__
+#define __UDPHUBLISTENER_H__
+
+#include <iostream>
+#include <stdexcept>
+
+#include <QThread>
+#include <QThreadPool>
+#include <QUdpSocket>
+#include <QHostAddress>
+#include <QTcpSocket>
+#include <QTcpServer>
+#include <QMutex>
+
+#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<JackTripWorker*>* 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<QString, uint16_t> 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 (file)
index 3c17676..0000000
+++ /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 <iostream>
-#include <cstdlib>
-#include <stdexcept>
-#include <cstring>
-
-#include <QTcpServer>
-#include <QTcpSocket>
-#include <QStringList>
-#include <QMutexLocker>
-
-#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<JackTripWorker*>;
-    for (int i = 0; i<gMaxThreads; i++) {
-        mJTWorkers->insert(i, NULL);
-    }
-
-
-    //mJTWorkers = new JackTripWorker(this);
-    mThreadPool.setExpiryTimeout(3000); // msec (-1) = forever
-    // Inizialize IP addresses
-    for (int i = 0; i<gMaxThreads; i++) {
-        mActiveAddress[i].address = ""; // Address strings
-        mActiveAddress[i].port = 0;
-    }
-    // Set the base dynamic port
-    // The Dynamic and/or Private Ports are those from 49152 through 65535
-    // mBasePort = ( rand() % ( (65535 - gMaxThreads) - 49152 ) ) + 49152;
-
-    // SoundWIRE ports open are UDP 61000-62000
-    mBasePort = 61000;
-
-    mUnderRunMode = JackTrip::WAVETABLE;
-    mBufferQueueLength = gDefaultQueueLength;
-}
-
-
-//*******************************************************************************
-UdpMasterListener::~UdpMasterListener()
-{
-    QMutexLocker lock(&mMutex);
-    mThreadPool.waitForDone();
-    //delete mJTWorker;
-    for (int i = 0; i<gMaxThreads; i++) {
-        delete mJTWorkers->at(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<mThreadPool.activeThreadCount()) )
-  {
-    if ( address==mActiveAddress[id][0] &&  port==mActiveAddress[id][1]) { busyAddress = true; }
-    id++;
-  }
-  */
-    for (int i = 0; i<gMaxThreads; i++) {
-        if ( address==mActiveAddress[i].address &&  port==mActiveAddress[i].port) {
-            id = i;
-            busyAddress = true;
-        }
-    }
-    if ( !busyAddress ) {
-        /*
-    mActiveAddress[id][0] = address;
-    mActiveAddress[id][1] = port;
-  } else {
-  */
-        id = 0;
-        bool foundEmptyAddress = false;
-        while ( !foundEmptyAddress && (id<gMaxThreads) ) {
-            if ( mActiveAddress[id].address.isEmpty() &&  (mActiveAddress[id].port == 0) ) {
-                foundEmptyAddress = true;
-                mActiveAddress[id].address = address;
-                mActiveAddress[id].port = port;
-            }  else {
-                id++;
-            }
-        }
-    }
-    if (!busyAddress) {
-        mTotalRunningThreads++;
-    }
-    return ((busyAddress) ? -1 : id);
-}
-
-
-//*******************************************************************************
-int UdpMasterListener::getPoolID(QString address, uint16_t port)
-{
-    QMutexLocker lock(&mMutex);
-    //for (int id = 0; id<mThreadPool.activeThreadCount(); id++ )
-    for (int id = 0; id<gMaxThreads; id++ )
-    {
-        if ( address==mActiveAddress[id].address &&  port==mActiveAddress[id].port)
-        { return id; }
-    }
-    return -1;
-}
-
-
-//*******************************************************************************
-int UdpMasterListener::releaseThread(int id)
-{
-    QMutexLocker lock(&mMutex);
-    mActiveAddress[id].address = "";
-    mActiveAddress[id].port = 0;
-    mTotalRunningThreads--;
-#ifdef WAIR // wair
-    if (isWAIR()) connectMesh(false); // invoked with -Sw
-#endif // endwhere
-    if (getHubPatch()) connectPatch(false); // invoked with -p > 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<gMaxThreads; id++ )
-    {
-        if ( !mActiveAddress[id].address.isEmpty() )
-        { qDebug() << id; }
-    }
-}
-#endif // endwhere
-
-#include "JMess.h"
-void UdpMasterListener::connectPatch(bool spawn)
-{
-    cout << ((spawn)?"spawning":"releasing") << " jacktripWorker so change patch" << endl;
-    JMess tmp;
-    // default is patch 0, which connects server audio to all clients
-    // these are the other cases:
-    if (getHubPatch() == JackTrip::RESERVEDMATRIX) // special patch for TU Berlin ensemble
-        tmp.connectTUB(gDefaultNumInChannels);
-    else if ((getHubPatch() == JackTrip::CLIENTECHO) || // client loopback for testing
-             (getHubPatch() == JackTrip::CLIENTFOFI) || // all clients to all clients except self
-             (getHubPatch() == JackTrip::FULLMIX)) // all clients to all clients including self
-        tmp.connectSpawnedPorts(gDefaultNumInChannels,getHubPatch());
-    // FIXME: need change to gDefaultNumInChannels if more than stereo
-}
-
-// TODO:
-// USE bool QAbstractSocket::isValid () const to check if socket is connect. if not, exit loop
diff --git a/src/UdpMasterListener.h b/src/UdpMasterListener.h
deleted file mode 100644 (file)
index 793a35a..0000000
+++ /dev/null
@@ -1,164 +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.h
- * \author Juan-Pablo Caceres and Chris Chafe
- * \date September 2008
- */
-
-#ifndef __UDPMASTERLISTENER_H__
-#define __UDPMASTERLISTENER_H__
-
-#include <iostream>
-#include <stdexcept>
-
-#include <QThread>
-#include <QThreadPool>
-#include <QUdpSocket>
-#include <QHostAddress>
-#include <QTcpSocket>
-#include <QTcpServer>
-#include <QMutex>
-
-#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<JackTripWorker*>* 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<QString, uint16_t> 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__
index 15011b4dfab60bddd8ecaf9fd78044cd6740ea97..e3f715094ca4ce1226721d54a525433bfc9a92b2 100755 (executable)
--- 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
index 590419f89128bec6342290beea274dea560d14f5..f898c63f4f9ef0ae8af47e83dc3188a080fc45c8 100644 (file)
@@ -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 {
index 9f31e6a0bef0175e141ef8227bc9e4d076383369..e0dfa08946b27d65aae1897b6c3d91d7c568570a 100644 (file)
@@ -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;