From: IOhannes m zmölnig (Debian/GNU) Date: Wed, 6 Apr 2022 08:17:58 +0000 (+0200) Subject: New upstream version 1.5.3+ds0 X-Git-Tag: archive/raspbian/2.5.1+ds-1+rpi1~1^2~9^2~21 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=ed3458dfc51ce4f4ac573ccdc8b94b8c32b6832a;p=jacktrip.git New upstream version 1.5.3+ds0 --- diff --git a/docs/Build/Linux.md b/docs/Build/Linux.md index 12c995a..698c760 100644 --- a/docs/Build/Linux.md +++ b/docs/Build/Linux.md @@ -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 index 0000000..28d4101 --- /dev/null +++ b/docs/CustomJackServerName.md @@ -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. diff --git a/docs/changelog.yml b/docs/changelog.yml index 1db1e26..d0d6023 100644 --- a/docs/changelog.yml +++ b/docs/changelog.yml @@ -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: diff --git a/jacktrip.pro b/jacktrip.pro index 3bb1cdd..0b2a5ee 100644 --- a/jacktrip.pro +++ b/jacktrip.pro @@ -22,6 +22,7 @@ equals(QT_EDITION, "OpenSource") { nogui { DEFINES += NO_GUI + QT -= gui } else { QT += gui QT += widgets diff --git a/mkdocs.yml b/mkdocs.yml index 705e991..aa3ca43 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -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 diff --git a/src/JackTrip.cpp b/src/JackTrip.cpp index 11df4a9..e841731 100644 --- a/src/JackTrip.cpp +++ b/src/JackTrip.cpp @@ -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) { diff --git a/src/Regulator.cpp b/src/Regulator.cpp index 1eb8d84..a9c8e51 100644 --- a/src/Regulator.cpp +++ b/src/Regulator.cpp @@ -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) diff --git a/src/Regulator.h b/src/Regulator.h index eb3da37..96d4e0e 100644 --- a/src/Regulator.h +++ b/src/Regulator.h @@ -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 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 mIncomingLost; + int mFPPratioNumerator; + int mFPPratioDenominator; + int mPartialPacketCnt; + bool mAuto; #ifdef GUIBS3 HerlperGUI* hg; void updateGUI(double msTol, int nSlots, int lostWin); diff --git a/src/UdpDataProtocol.cpp b/src/UdpDataProtocol.cpp index c1226ec..6f61ad1 100644 --- a/src/UdpDataProtocol.cpp +++ b/src/UdpDataProtocol.cpp @@ -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; diff --git a/src/jacktrip_globals.h b/src/jacktrip_globals.h index 7513b1f..b71be81 100644 --- a/src/jacktrip_globals.h +++ b/src/jacktrip_globals.h @@ -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