New upstream version 1.5.3+ds0
authorIOhannes m zmölnig (Debian/GNU) <umlaeute@debian.org>
Wed, 6 Apr 2022 08:17:58 +0000 (10:17 +0200)
committerIOhannes m zmölnig (Debian/GNU) <umlaeute@debian.org>
Wed, 6 Apr 2022 08:17:58 +0000 (10:17 +0200)
docs/Build/Linux.md
docs/CustomJackServerName.md [new file with mode: 0644]
docs/changelog.yml
jacktrip.pro
mkdocs.yml
src/JackTrip.cpp
src/Regulator.cpp
src/Regulator.h
src/UdpDataProtocol.cpp
src/jacktrip_globals.h

index 12c995a7493ec9b62a03a92fb235346ba572c642..698c760ff714f960e8770eff13bf81af06e5d046 100644 (file)
@@ -134,3 +134,35 @@ Copyright (c) 2008-2020 Juan-Pablo Caceres, Chris Chafe.
 SoundWIRE group at CCRMA, Stanford University
 ```
 
+### Running Two Versions of JackTrip in Parallel
+One level above the project directory of your current JackTrip installation, clone the JackTrip repository again in another directory (e.g. `jacktrip-1.x.x`):
+
+```sh
+$ git clone --recurse-submodules https://github.com/jacktrip/jacktrip.git jacktrip-1.x.x
+```
+
+You now have two separate folders side by side: the new version in the jacktrip-1.x.x folder and the original one in the jacktrip folder. To build the new version without installing it:
+```sh
+$ cd jacktrip-1.x.x
+$ ./build
+```
+
+To experiment with the new version of JackTrip, enter builddir/build directory and check the JackTrip version:  
+```sh
+$ cd builddir
+$ ./jacktrip -v
+```
+
+You can use JackTrip from this directory, e.g.:
+```sh
+$ ./jacktrip -C serveraddress
+```
+
+You can switch back and forth between different JackTrip versions by running them in their respective build directories.
+
+Hint: If you lose track of where you are, this command will show your present working directory:
+```sh
+$ pwd
+```
+
+The new version's directory structure might look like this: ``` jacktrip-1.x.x/builddir``` and the old version ``` jacktrip/builddir```.
diff --git a/docs/CustomJackServerName.md b/docs/CustomJackServerName.md
new file mode 100644 (file)
index 0000000..28d4101
--- /dev/null
@@ -0,0 +1,8 @@
+# Using custom JACK server name
+
+In case you want to use JackTrip with JACK server _that has non-default name_ (by default it is `default`), you need to set `JACK_DEFAULT_SERVER` environment variable for JackTrip.
+
+1. Run `jackd` with `--name` flag:`jackd --name myfancyserver ...`
+2. Run JackTrip with required environment variable set: `JACK_DEFAULT_SERVER=myfancyserver jacktrip ...`
+
+This is useful when you want to isolate multiple JackTrip instances on single machine.
index 1db1e2637c89018656138db02fd321122c860361..d0d602319d5bfc5d3bf4673f537aa6e4cae81707 100644 (file)
@@ -1,3 +1,12 @@
+- Version: "1.5.3"
+  Date: 2022-03-28
+  Description:
+  - (added) linux instructions for parallel versions
+  - (added) docs on running JackTrip with a named JACK server
+  - (added) nogui linux release build
+  - (update) Auto mode for buffer strategy 3
+  - (update) remove extra macOS binary release artifact
+  - (fixed) Don't link nogui qmake build with gui libraries
 - Version: "1.5.2"
   Date: 2022-03-02
   Description:
index 3bb1cddf0955c962e8ca3888df68fd95de0f1d05..0b2a5ee3b07b1433e9b179e2b50f56d770b53120 100644 (file)
@@ -22,6 +22,7 @@ equals(QT_EDITION, "OpenSource") {
 
 nogui {
   DEFINES += NO_GUI
+  QT -= gui
 } else {
   QT += gui
   QT += widgets
index 705e991c9be3ecfa44cfab7e309df36d10357fd5..aa3ca4347477034af0fa0d1801eda876991f4003 100644 (file)
@@ -5,6 +5,7 @@ nav:
   - Home: index.md
   - User Guide:
     - Installation: Install.md
+    - Using custom JACK server name: CustomJackServerName.md
   - Developer Guide:
     - QMake Build:
       - Linux: Build/Linux.md
index 11df4a93a61b6ce7222645609b335e6827ca4a8a..e841731719e202f1592561bd6eb46c8eab3edd3e 100644 (file)
@@ -377,15 +377,15 @@ void JackTrip::setupRingBuffers()
                 new RingBuffer(audio_output_slot_size, mBufferQueueLength);
             mPacketHeader->setBufferRequiresSameSettings(true);
         } else if (mBufferStrategy == 3) {
-            qDebug() << "experimental buffer strategy 3 -- pool buffer with PLC";
+            qDebug() << "experimental buffer strategy 3 -- regulator with PLC";
             mSendRingBuffer =
                 new RingBuffer(audio_input_slot_size, gDefaultOutputQueueLength);
             mReceiveRingBuffer =
-                new Regulator(mSampleRate, mNumAudioChansIn, mAudioBitResolution,
+                new Regulator(mSampleRate, mNumAudioChansOut, mAudioBitResolution,
                               mAudioBufferSize, mBufferQueueLength);
             // bufStrategy 3, mBufferQueueLength is in integer msec not packets
 
-            mPacketHeader->setBufferRequiresSameSettings(true);
+            mPacketHeader->setBufferRequiresSameSettings(false);  // = asym is default
         } else {
             cout << "Using JitterBuffer strategy " << mBufferStrategy << endl;
             if (0 > mBufferQueueLength) {
index 1eb8d8415048f3d080384ec8fda5081169556956..a9c8e51fe4b842ec79d367d4ed540d84bd7cb0aa 100644 (file)
@@ -51,7 +51,7 @@
 // use jack_iodelay
 // use jmess -s delay.xml and jmess -c delay.xml
 
-// tested outgoing loss impairments with
+// tested outgoing loss impairments with (replace lo with relevant network interface)
 // sudo tc qdisc add dev lo root netem loss 2%
 // sudo tc qdisc del dev lo root netem loss 2%
 // tested jitter impairments with
@@ -85,7 +85,12 @@ Regulator::Regulator(int sample_rate, int channels, int bit_res, int FPP, int qL
     , mFPP(FPP)
     , mSampleRate(sample_rate)
     , mMsecTolerance((double)qLen)
+    , mAuto(false)
 {
+    if (mMsecTolerance < 0.0) {  // handle, for example, CLI -q auto15 or -q auto
+        mAuto = true;
+        mMsecTolerance *= -1.0;
+    };
     switch (mAudioBitRes) {  // int from JitterBuffer to AudioInterface enum
     case 1:
         mBitResolutionMode = AudioInterface::audioBitResolutionT::BIT8;
@@ -136,8 +141,10 @@ Regulator::Regulator(int sample_rate, int channels, int bit_res, int FPP, int qL
     }
     mZeros = new int8_t[mBytes];
     memcpy(mZeros, mXfrBuffer, mBytes);
-    pushStat       = new StdDev((int)(floor(48000.0 / (double)mFPP)), 1);
-    pullStat       = new StdDev((int)(floor(48000.0 / (double)mFPP)), 2);
+    mAssembledPacket = new int8_t[mBytes];  // for asym
+    memcpy(mAssembledPacket, mXfrBuffer, mBytes);
+    pushStat       = new StdDev(&mIncomingTimer, (int)(floor(48000.0 / (double)mFPP)), 1);
+    pullStat       = new StdDev(&mIncomingTimer, (int)(floor(48000.0 / (double)mFPP)), 2);
     mLastLostCount = 0;  // for stats
     mIncomingTimer.start();
     mLastSeqNumIn  = -1;
@@ -146,7 +153,12 @@ Regulator::Regulator(int sample_rate, int channels, int bit_res, int FPP, int qL
     mIncomingTiming.resize(ModSeqNumInit);
     for (int i = 0; i < ModSeqNumInit; i++)
         mIncomingTiming[i] = 0.0;
-    mModSeqNum = mNumSlots * 2;
+    mModSeqNum           = mNumSlots * 2;
+    mFPPratioNumerator   = 1;
+    mFPPratioDenominator = 1;
+    mPartialPacketCnt    = 0;
+    mFPPratioIsSet       = false;
+    mBytesPeerPacket     = mBytes;
 #ifdef GUIBS3
     // hg for GUI
     hg = new HerlperGUI(qApp->activeWindow());
@@ -184,8 +196,8 @@ void Regulator::changeGlobal_3(int x)
 
 void Regulator::printParams()
 {
-    qDebug() << "mMsecTolerance" << mMsecTolerance << "mNumSlots" << mNumSlots
-             << "mModSeqNum" << mModSeqNum << "mLostWindow" << mLostWindow;
+//    qDebug() << "mMsecTolerance" << mMsecTolerance << "mNumSlots" << mNumSlots
+//             << "mModSeqNum" << mModSeqNum << "mLostWindow" << mLostWindow;
 #ifdef GUIBS3
     updateGUI((int)mMsecTolerance, mNumSlots);
 #endif
@@ -205,10 +217,60 @@ Regulator::~Regulator()
     for (int i = 0; i < mNumChannels; i++)
         delete mChanData[i];
 }
+
+void Regulator::setFPPratio(int len)
+{
+    int peerFPP = len / (mNumChannels * mBitResolutionMode);
+    if (peerFPP != mFPP) {
+        if (peerFPP > mFPP)
+            mFPPratioDenominator = peerFPP / mFPP;
+        else
+            mFPPratioNumerator = mFPP / peerFPP;
+        qDebug() << "peerBuffers / localBuffers" << mFPPratioNumerator << " / "
+                 << mFPPratioDenominator;
+    }
+    if (mFPPratioNumerator > 1)
+        mBytesPeerPacket = mBytes / mFPPratioNumerator;
+    mFPPratioIsSet = true;
+}
+
+//*******************************************************************************
+void Regulator::shimFPP(const int8_t* buf, int len, int seq_num)
+{
+    if (seq_num != -1) {
+        if (!mFPPratioIsSet)
+            setFPPratio(len);
+        if (mFPPratioNumerator > 1) {  // 2/1, 4/1 peer FPP is lower
+            int modSeqNumPeer = mModSeqNum * mFPPratioNumerator;
+            seq_num %= modSeqNumPeer;
+            //        qDebug() << seq_num << seq_num / mFPPratioNumerator <<
+            //        mPartialPacketCnt;
+            seq_num /= mFPPratioNumerator;
+            int tmp = (mPartialPacketCnt % mFPPratioNumerator) * mBytesPeerPacket;
+            memcpy(&mAssembledPacket[tmp], buf, mBytesPeerPacket);
+            if ((mPartialPacketCnt % mFPPratioNumerator) == (mFPPratioNumerator - 1))
+                pushPacket(mAssembledPacket, seq_num);
+            mPartialPacketCnt++;
+        } else if (mFPPratioDenominator > 1) {  // 1/2, 1/4 peer FPP is higher
+            int modSeqNumPeer = mModSeqNum / mFPPratioDenominator;
+            seq_num %= modSeqNumPeer;
+            seq_num *= mFPPratioDenominator;
+            for (int i = 0; i < mFPPratioDenominator; i++) {
+                int tmp = i * mBytes;
+                memcpy(mAssembledPacket, &buf[tmp], mBytes);
+                pushPacket(mAssembledPacket, seq_num);
+                seq_num++;
+            }
+        } else
+            pushPacket(buf, seq_num);
+    }
+};
+
 //*******************************************************************************
 void Regulator::pushPacket(const int8_t* buf, int seq_num)
 {
     QMutexLocker locker(&mMutex);
+    //    qDebug() << "\t" << seq_num;
     seq_num %= mModSeqNum;
     // if (seq_num==0) return;   // if (seq_num==1) return; // impose regular loss
     mIncomingTiming[seq_num] =
@@ -216,7 +278,12 @@ void Regulator::pushPacket(const int8_t* buf, int seq_num)
     mLastSeqNumIn = seq_num;
     if (mLastSeqNumIn != -1)
         memcpy(mSlots[mLastSeqNumIn % mNumSlots], buf, mBytes);
-    pushStat->tick();
+    double nowMS = pushStat->tick();
+    if (mAuto && (nowMS > 2000.0)) {
+        double tmp = pushStat->longTermStdDev + pushStat->longTermMax;
+        tmp += 2.0;  // 2 ms -- kind of a guess
+        changeGlobal(tmp);
+    }
 };
 
 //*******************************************************************************
@@ -508,17 +575,18 @@ ChanData::ChanData(int i, int FPP, int hist) : ch(i)
 }
 
 //*******************************************************************************
-StdDev::StdDev(int w, int id) : window(w), mId(id)
+StdDev::StdDev(QElapsedTimer* timer, int w, int id) : mTimer(timer), window(w), mId(id)
 {
     reset();
     longTermStdDev    = 0.0;
     longTermStdDevAcc = 0.0;
     longTermCnt       = 0;
     lastMean          = 0.0;
-    lastMin           = 0;
-    lastMax           = 0;
-    lastPlcUnderruns  = 0;
-    mTimer.start();
+    lastMin           = 0.0;
+    lastMax           = 0.0;
+    longTermMax       = 0.0;
+    longTermMaxAcc    = 0.0;
+    lastTime          = 0.0;
     data.resize(w, 0.0);
 }
 
@@ -535,8 +603,9 @@ void StdDev::reset()
 
 double StdDev::tick()
 {
-    double msElapsed = (double)mTimer.nsecsElapsed() / 1000000.0;
-    mTimer.start();
+    double now       = (double)mTimer->nsecsElapsed() / 1000000.0;
+    double msElapsed = now - lastTime;
+    lastTime         = now;
     if (ctr != window) {
         data[ctr] = msElapsed;
         if (msElapsed < min)
@@ -557,6 +626,8 @@ double StdDev::tick()
         if (longTermCnt) {
             longTermStdDevAcc += stdDev;
             longTermStdDev = longTermStdDevAcc / (double)longTermCnt;
+            longTermMaxAcc += max;
+            longTermMax = longTermMaxAcc / (double)longTermCnt;
             if (gVerboseFlag)
                 cout << setw(10) << mean << setw(10) << lastMin << setw(10) << max
                      << setw(10) << stdDev << setw(10) << longTermStdDev << " " << mId
@@ -567,14 +638,13 @@ double StdDev::tick()
                     "stdDev / longTermStdDev) \n";
 
         longTermCnt++;
-        lastMean         = mean;
-        lastMin          = min;
-        lastMax          = max;
-        lastStdDev       = stdDev;
-        lastPlcUnderruns = plcUnderruns;
+        lastMean   = mean;
+        lastMin    = min;
+        lastMax    = max;
+        lastStdDev = stdDev;
         reset();
     }
-    return msElapsed;
+    return lastTime;
 }
 //*******************************************************************************
 bool Regulator::getStats(RingBuffer::IOStat* stat, bool reset)
index eb3da37a805dd9e1692dee7aaa864643a43f83f6..96d4e0efa4ea80c36d37c1bd0f34d575914d1367 100644 (file)
@@ -95,10 +95,10 @@ class ChanData
 class StdDev
 {
    public:
-    StdDev(int w, int id);
+    StdDev(QElapsedTimer* timer, int w, int id);
     void reset();
     double tick();
-    QElapsedTimer mTimer;
+    QElapsedTimer* mTimer;
     std::vector<double> data;
     double mean;
     double var;
@@ -112,12 +112,15 @@ class StdDev
     double lastMean;
     double lastMin;
     double lastMax;
+    int plcUnderruns;
+    int lastPlcUnderruns;
     double lastStdDev;
     double longTermStdDev;
     double longTermStdDevAcc;
+    double longTermMax;
+    double longTermMaxAcc;
+    double lastTime;
     int longTermCnt;
-    int plcUnderruns;
-    int lastPlcUnderruns;
 };
 
 #ifdef GUIBS3
@@ -134,17 +137,17 @@ class Regulator : public RingBuffer
     Regulator(int sample_rate, int channels, int bit_res, int FPP, int qLen);
     virtual ~Regulator();
 
+    void shimFPP(const int8_t* buf, int len, int seq_num);
     void pushPacket(const int8_t* buf, int seq_num);
     // can hijack unused2 to propagate incoming seq num if needed
     // option is in UdpDataProtocol
     // if (!mJackTrip->writeAudioBuffer(src, host_buf_size, last_seq_num))
     // instread of
     // if (!mJackTrip->writeAudioBuffer(src, host_buf_size, gap_size))
-    virtual bool insertSlotNonBlocking(const int8_t* ptrToSlot,
-                                       [[maybe_unused]] int unused,
+    virtual bool insertSlotNonBlocking(const int8_t* ptrToSlot, [[maybe_unused]] int len,
                                        [[maybe_unused]] int seq_num)
     {
-        pushPacket(ptrToSlot, seq_num);
+        shimFPP(ptrToSlot, len, seq_num);
         return (true);
     }
 
@@ -156,6 +159,8 @@ class Regulator : public RingBuffer
     virtual bool getStats(IOStat* stat, bool reset);
 
    private:
+    void setFPPratio(int len);
+    bool mFPPratioIsSet;
     void processPacket(bool glitch);
     void processChannel(int ch, bool glitch, int packetCnt, bool lastWasGlitch);
     int mNumChannels;
@@ -168,7 +173,9 @@ class Regulator : public RingBuffer
     AudioInterface::audioBitResolutionT mBitResolutionMode;
     BurgAlgorithm ba;
     int mBytes;
+    int mBytesPeerPacket;
     int8_t* mXfrBuffer;
+    int8_t* mAssembledPacket;
     int mPacketCnt;
     sample_t bitsToSample(int ch, int frame);
     void sampleToBits(sample_t sample, int ch, int frame);
@@ -190,7 +197,10 @@ class Regulator : public RingBuffer
     int mModSeqNum;
     int mLostWindow;
     int mSkip;
-    std::vector<bool> mIncomingLost;
+    int mFPPratioNumerator;
+    int mFPPratioDenominator;
+    int mPartialPacketCnt;
+    bool mAuto;
 #ifdef GUIBS3
     HerlperGUI* hg;
     void updateGUI(double msTol, int nSlots, int lostWin);
index c1226ec126b60d01c3b51364c0e3e6860751f34a..6f61ad12b1af5fa6508695d68098f7c12abd43b4 100644 (file)
@@ -811,8 +811,7 @@ void UdpDataProtocol::receivePacketRedundancy(
         int ok = true; // send audio buf to
         ok = (mJackTrip->getBufferStrategy() !=3) ? // ring or jitter
                     mJackTrip->writeAudioBuffer(src, host_buf_size, gap_size)
-                  : // regulator needs matching local and peer buffer settings
-                    mJackTrip->writeAudioBuffer(src, host_buf_size, last_seq_num);
+                  : mJackTrip->writeAudioBuffer(src, host_buf_size, last_seq_num);
         if (!ok) {
             emit signalError("Local and Peer buffer settings are incompatible");
             cout << "ERROR: Local and Peer buffer settings are incompatible" << endl;
index 7513b1fc799a9fecb14222cc8bc3c59a5711f92d..b71be8120c724b1ce091347925968f7d14471f1d 100644 (file)
@@ -40,7 +40,7 @@
 
 #include "AudioInterface.h"
 
-constexpr const char* const gVersion = "1.5.2";  ///< JackTrip version
+constexpr const char* const gVersion = "1.5.3";  ///< JackTrip version
 
 //*******************************************************************************
 /// \name Default Values