diff --git a/src/analyzerconsole.cpp b/src/analyzerconsole.cpp index 5233fb12..9b195b0a 100644 --- a/src/analyzerconsole.cpp +++ b/src/analyzerconsole.cpp @@ -41,7 +41,8 @@ CAnalyzerConsole::CAnalyzerConsole ( CClient* pNCliP, GraphFrameColor ( Qt::black ), // frame GraphGridColor ( Qt::gray ), // grid LineColor ( Qt::blue ), - LineLimitColor ( Qt::red ) + LineLimitColor ( Qt::green ), + LineMaxUpLimitColor ( Qt::red ) { // set the window icon and title text const QIcon icon = QIcon ( QString::fromUtf8 ( ":/png/main/res/mainicon.png" ) ); @@ -126,14 +127,16 @@ void CAnalyzerConsole::DrawErrorRateTrace() // get the network buffer error rates to be displayed CVector vecButErrorRates; double dLimit; + double dMaxUpLimit; - pClient->GetBufErrorRates ( vecButErrorRates, dLimit ); + pClient->GetBufErrorRates ( vecButErrorRates, dLimit, dMaxUpLimit ); // get the number of data elements const int iNumBuffers = vecButErrorRates.Size(); - // convert the limit in the log domain - const double dLogLimit = log10 ( dLimit ); + // convert the limits in the log domain + const double dLogLimit = log10 ( dLimit ); + const double dLogMaxUpLimit = log10 ( dMaxUpLimit ); // use fixed y-axis scale where the limit line is in the middle of the graph const double dMax = 0; @@ -154,6 +157,17 @@ void CAnalyzerConsole::DrawErrorRateTrace() QPoint ( GraphGridFrame.x() + GraphGridFrame.width(), dYValLimitInGraph ) ); + // plot the maximum upper limit line as a dashed line + const double dYValMaxUpLimitInGraph = CalcYPosInGraph ( dMin, dMax, dLogMaxUpLimit ); + + GraphPainter.setPen ( QPen ( QBrush ( LineMaxUpLimitColor ), + iLineWidth, + Qt::DashLine ) ); + + GraphPainter.drawLine ( QPoint ( GraphGridFrame.x(), dYValMaxUpLimitInGraph ), + QPoint ( GraphGridFrame.x() + + GraphGridFrame.width(), dYValMaxUpLimitInGraph ) ); + // plot the data for ( int i = 0; i < iNumBuffers; i++ ) { diff --git a/src/analyzerconsole.h b/src/analyzerconsole.h index 3a472bcd..1338dabe 100644 --- a/src/analyzerconsole.h +++ b/src/analyzerconsole.h @@ -82,6 +82,7 @@ protected: QColor GraphGridColor; QColor LineColor; QColor LineLimitColor; + QColor LineMaxUpLimitColor; QTimer TimerErrRateUpdate; diff --git a/src/buffer.cpp b/src/buffer.cpp index 0f99ef5b..282fbed5 100755 --- a/src/buffer.cpp +++ b/src/buffer.cpp @@ -115,7 +115,8 @@ CNetBufWithStats::CNetBufWithStats() : } void CNetBufWithStats::GetErrorRates ( CVector& vecErrRates, - double& dLimit ) + double& dLimit, + double& dMaxUpLimit ) { // get all the averages of the error statistic vecErrRates.Init ( NUM_STAT_SIMULATION_BUFFERS ); @@ -125,8 +126,9 @@ void CNetBufWithStats::GetErrorRates ( CVector& vecErrRates, vecErrRates[i] = ErrorRateStatistic[i].GetAverage(); } - // get the limit for decision - dLimit = ERROR_RATE_BOUND; + // get the limits for the decisions + dLimit = ERROR_RATE_BOUND; + dMaxUpLimit = UP_MAX_ERROR_BOUND; } void CNetBufWithStats::Init ( const int iNewBlockSize, @@ -199,14 +201,17 @@ bool CNetBufWithStats::Get ( CVector& vecbyData, void CNetBufWithStats::UpdateAutoSetting() { - int iCurDecision = 0; // dummy initialization - bool bDecisionFound = false; + int iCurDecision = 0; // dummy initialization + int iCurMaxUpDecision = 0; // dummy initialization + bool bDecisionFound; - // Get error rate decision ------------------------------------------------- + // Get regular error rate decision ----------------------------------------- // Use a specified error bound to identify the best buffer size for the // current network situation. Start with the smallest buffer and // test for the error rate until the rate is below the bound. + bDecisionFound = false; + for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS - 1; i++ ) { if ( ( !bDecisionFound ) && @@ -224,6 +229,30 @@ void CNetBufWithStats::UpdateAutoSetting() } + // Get maximum upper error rate decision ----------------------------------- + // Use a specified error bound to identify the maximum upper error rate + // to identify if we have a too low buffer setting which gives a very + // bad performance constantly. Start with the smallest buffer and + // test for the error rate until the rate is below the bound. + bDecisionFound = false; + + for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS - 1; i++ ) + { + if ( ( !bDecisionFound ) && + ( ErrorRateStatistic[i].GetAverage() <= UP_MAX_ERROR_BOUND ) ) + { + iCurMaxUpDecision = viBufSizesForSim[i]; + bDecisionFound = true; + } + } + + if ( !bDecisionFound ) + { + // in case no buffer is below bound, use largest buffer size + iCurMaxUpDecision = viBufSizesForSim[NUM_STAT_SIMULATION_BUFFERS - 1]; + } + + // Post calculation (filtering) -------------------------------------------- // Define different weigths for up and down direction. Up direction // filtering shall be slower than for down direction since we assume @@ -235,9 +264,10 @@ void CNetBufWithStats::UpdateAutoSetting() // adaptation. // Note that the following definitions of the weigh constants assume a block // size of 128 samples at a sampling rate of 48 kHz. - double dWeightUp = 0.999995; - double dWeightDown = 0.9999; - const double dHysteresisValue = 0.1; + double dWeightUp = 0.999995; + double dWeightDown = 0.9999; + const double dHysteresisValue = 0.1; + bool bUseFastAdaptation = false; // check for initialization phase if ( iInitCounter > 0 ) @@ -245,6 +275,20 @@ void CNetBufWithStats::UpdateAutoSetting() // decrease init counter iInitCounter--; + // use the fast adaptation + bUseFastAdaptation = true; + } + + // if the current detected buffer setting is below the maximum upper bound + // decision, then we enable a booster to go up to the minimum required + // number of buffer blocks (i.e. we use weights for fast adaptation) + if ( iCurAutoBufferSizeSetting < iCurMaxUpDecision ) + { + bUseFastAdaptation = true; + } + + if ( bUseFastAdaptation ) + { // overwrite weigth values with lower values dWeightUp = 0.9995; dWeightDown = 0.999; @@ -256,6 +300,22 @@ void CNetBufWithStats::UpdateAutoSetting() dWeightUp, dWeightDown ); +/* +// TEST store important detection parameters in file for debugging +static FILE* pFile = fopen ( "test.dat", "w" ); +static int icnt = 0; +if ( icnt == 50 ) +{ + fprintf ( pFile, "%d %e\n", iCurDecision, dCurIIRFilterResult ); + fflush ( pFile ); + icnt = 0; +} +else +{ + icnt++; +} +*/ + // apply a hysteresis iCurAutoBufferSizeSetting = MathUtils().DecideWithHysteresis ( dCurIIRFilterResult, diff --git a/src/buffer.h b/src/buffer.h index c2873c73..a29be43d 100755 --- a/src/buffer.h +++ b/src/buffer.h @@ -34,9 +34,14 @@ // blocks we have 15 s / 2.66 ms * 2 = approx. 11000 #define MAX_STATISTIC_COUNT 11000 -// definition of the error bound +// definition of the upper error bound of the jitter buffers #define ERROR_RATE_BOUND 0.001 +// definition of the upper jitter buffer error bound, if that one is reached we +// have to speed up the filtering to quickly get out of a incorrect buffer +// size state +#define UP_MAX_ERROR_BOUND 0.01 + // number of simulation network jitter buffers for evaluating the statistic #define NUM_STAT_SIMULATION_BUFFERS 11 @@ -407,7 +412,9 @@ public: virtual bool Get ( CVector& vecbyData, const int iOutSize ); int GetAutoSetting() { return iCurAutoBufferSizeSetting; } - void GetErrorRates ( CVector& vecErrRates, double& dLimit ); + void GetErrorRates ( CVector& vecErrRates, + double& dLimit, + double& dMaxUpLimit ); protected: void UpdateAutoSetting(); diff --git a/src/channel.h b/src/channel.h index a600b432..2d002154 100755 --- a/src/channel.h +++ b/src/channel.h @@ -136,8 +136,8 @@ Protocol.CreateChanNameMes ( ChInfo.strName ); int GetNetwFrameSizeFact() const { return iNetwFrameSizeFact; } int GetNetwFrameSize() const { return iNetwFrameSize; } - void GetBufErrorRates ( CVector& vecErrRates, double& dLimit ) - { SockBuf.GetErrorRates ( vecErrRates, dLimit ); } + void GetBufErrorRates ( CVector& vecErrRates, double& dLimit, double& dMaxUpLimit ) + { SockBuf.GetErrorRates ( vecErrRates, dLimit, dMaxUpLimit ); } EAudComprType GetAudioCompressionType() { return eAudioCompressionType; } int GetNumAudioChannels() const { return iNumAudioChannels; } diff --git a/src/client.h b/src/client.h index de10780b..521013e3 100755 --- a/src/client.h +++ b/src/client.h @@ -275,8 +275,8 @@ public: int EstimatedOverallDelay ( const int iPingTimeMs ); - void GetBufErrorRates ( CVector& vecErrRates, double& dLimit ) - { Channel.GetBufErrorRates ( vecErrRates, dLimit ); } + void GetBufErrorRates ( CVector& vecErrRates, double& dLimit, double& dMaxUpLimit ) + { Channel.GetBufErrorRates ( vecErrRates, dLimit, dMaxUpLimit ); } // settings CVector vstrIPAddress;