-
Notifications
You must be signed in to change notification settings - Fork 246
Expand file tree
/
Copy pathbuffer.h
More file actions
436 lines (361 loc) · 13.6 KB
/
Copy pathbuffer.h
File metadata and controls
436 lines (361 loc) · 13.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
/******************************************************************************\
* Copyright (c) 2004-2026
*
* Author(s):
* Volker Fischer
*
******************************************************************************
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
\******************************************************************************/
#pragma once
#include "util.h"
#include "global.h"
/* Definitions ****************************************************************/
// number of simulation network jitter buffers for evaluating the statistic
// NOTE If you want to change this number, the code has to modified, too!
#define NUM_STAT_SIMULATION_BUFFERS 10
// hysteresis for buffer size decision to avoid fast changes if close to the bound
#define FILTER_DECISION_HYSTERESIS 0.1
// definition of the upper error bound of the jitter buffers
#define ERROR_RATE_BOUND_DOUBLE_FRAME_SIZE 0.0005
#define ERROR_RATE_BOUND ( ERROR_RATE_BOUND_DOUBLE_FRAME_SIZE / 2 )
// 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_DOUBLE_FRAME_SIZE 0.01
#define UP_MAX_ERROR_BOUND ( UP_MAX_ERROR_BOUND_DOUBLE_FRAME_SIZE / 2 )
// each regular buffer access lead to a count for put and get, assuming 2.66 ms
// blocks we have 15 s / 2.66 ms * 2 = approx. 11000
#define MAX_STATISTIC_COUNT_DOUBLE_FRAME_SIZE 11000
// each regular buffer access lead to a count for put and get, assuming 1.33 ms
// blocks we have 15 s / 1.33 ms * 2 = approx. 22500
#define MAX_STATISTIC_COUNT 22500
// Note that the following definitions of the weigh constants assume a block
// size of 128 samples at a sampling rate of 48 kHz.
#define IIR_WEIGTH_UP_NORMAL_DOUBLE_FRAME_SIZE 0.999995
#define IIR_WEIGTH_DOWN_NORMAL_DOUBLE_FRAME_SIZE 0.9999
#define IIR_WEIGTH_UP_FAST_DOUBLE_FRAME_SIZE 0.9995
#define IIR_WEIGTH_DOWN_FAST_DOUBLE_FRAME_SIZE 0.999
// convert numbers from 128 samples case using http://www.tsdconseil.fr/tutos/tuto-iir1-en.pdf
// and https://octave-online.net:
// gamma = exp(-Ts/tau), after some calculations we get: x=0.999995;exp(64/128*log(x))
#define IIR_WEIGTH_UP_NORMAL 0.9999975
#define IIR_WEIGTH_DOWN_NORMAL 0.99994999875
#define IIR_WEIGTH_UP_FAST 0.9997499687422
#define IIR_WEIGTH_DOWN_FAST 0.999499875
/* Classes ********************************************************************/
// Buffer base class -----------------------------------------------------------
template<class TData>
class CBuffer
{
public:
CBuffer() {}
void Init ( const int iNewMemSize )
{
// allocate memory for actual data buffer
vecMemory.Init ( iNewMemSize );
// init buffer pointers and buffer state (empty buffer)
iGetPos = 0;
iPutPos = 0;
eBufState = BS_EMPTY;
// store total memory size value
iMemSize = iNewMemSize;
}
virtual bool Put ( const CVector<TData>& vecData, const int iInSize )
{
// copy new data in internal buffer
int iCurPos = 0;
if ( iPutPos + iInSize > iMemSize )
{
// remaining space size for second block
const int iRemSpace = iPutPos + iInSize - iMemSize;
// data must be written in two steps because of wrap around
while ( iPutPos < iMemSize )
{
vecMemory[iPutPos++] = vecData[iCurPos++];
}
for ( iPutPos = 0; iPutPos < iRemSpace; iPutPos++ )
{
vecMemory[iPutPos] = vecData[iCurPos++];
}
}
else
{
// data can be written in one step
std::copy ( vecData.begin(), vecData.begin() + iInSize, vecMemory.begin() + iPutPos );
// set the put position one block further (no wrap around needs
// to be considered here)
iPutPos += iInSize;
}
// take care about wrap around of put pointer
if ( iPutPos == iMemSize )
{
iPutPos = 0;
}
// set buffer state flag
if ( iPutPos == iGetPos )
{
eBufState = BS_FULL;
}
else
{
eBufState = BS_OK;
}
return true; // no error check in base class, always return ok
}
virtual bool Get ( CVector<TData>& vecData, const int iOutSize )
{
// copy data from internal buffer in output buffer
int iCurPos = 0;
if ( iGetPos + iOutSize > iMemSize )
{
// remaining data size for second block
const int iRemData = iGetPos + iOutSize - iMemSize;
// data must be read in two steps because of wrap around
while ( iGetPos < iMemSize )
{
vecData[iCurPos++] = vecMemory[iGetPos++];
}
for ( iGetPos = 0; iGetPos < iRemData; iGetPos++ )
{
vecData[iCurPos++] = vecMemory[iGetPos];
}
}
else
{
// data can be read in one step
std::copy ( vecMemory.begin() + iGetPos, vecMemory.begin() + iGetPos + iOutSize, vecData.begin() );
// set the get position one block further (no wrap around needs
// to be considered here)
iGetPos += iOutSize;
}
// take care about wrap around of get pointer
if ( iGetPos == iMemSize )
{
iGetPos = 0;
}
// set buffer state flag
if ( iPutPos == iGetPos )
{
eBufState = BS_EMPTY;
}
else
{
eBufState = BS_OK;
}
return true; // no error check in base class, always return ok
}
virtual int GetAvailData() const
{
// calculate available data in buffer
int iAvData = iPutPos - iGetPos;
// check for special case and wrap around
if ( iAvData < 0 )
{
iAvData += iMemSize; // wrap around
}
else
{
if ( ( iAvData == 0 ) && ( eBufState == BS_FULL ) )
{
iAvData = iMemSize;
}
}
return iAvData;
}
bool isFull() const { return eBufState == BS_FULL; }
bool isEmpty() const { return eBufState == BS_EMPTY; }
protected:
enum EBufState
{
BS_OK,
BS_FULL,
BS_EMPTY
};
CVector<TData> vecMemory;
int iMemSize;
int iGetPos;
int iPutPos;
EBufState eBufState;
};
// Network buffer (jitter buffer) ----------------------------------------------
class CNetBuf
{
public:
CNetBuf ( const bool bNIsSim = false ) : iSequenceNumberAtGetPos ( 0 ), bIsSimulation ( bNIsSim ), bIsInitialized ( false ) {}
void Init ( const int iNewBlockSize, const int iNewNumBlocks, const bool bNUseSequenceNumber, const bool bPreserve = false );
void SetIsSimulation ( const bool bNIsSim ) { bIsSimulation = bNIsSim; }
virtual bool Put ( const CVector<uint8_t>& vecbyData, int iInSize );
virtual bool Get ( CVector<uint8_t>& vecbyData, const int iOutSize );
protected:
enum EBufState
{
BS_OK,
BS_FULL,
BS_EMPTY
};
int GetAvailSpace() const;
int GetAvailData() const;
void Resize ( const int iNewNumBlocks, const int iNewBlockSize );
CVector<CVector<uint8_t>> vecvecMemory;
CVector<int> veciBlockValid;
int iNumBlocksMemory;
int iBlockGetPos;
int iBlockPutPos;
int iBlockSize;
uint8_t iSequenceNumberAtGetPos; // uint8_t so that it wraps automatically
EBufState eBufState;
bool bUseSequenceNumber;
bool bIsSimulation;
bool bIsInitialized;
static constexpr int iNumBytesSeqNum = 1; // per definition 1 byte sequence counter
};
// Network buffer (jitter buffer) with statistic calculations ------------------
class CNetBufWithStats : public CNetBuf
{
public:
CNetBufWithStats();
void Init ( const int iNewBlockSize, const int iNewNumBlocks, const bool bNUseSequenceNumber, const bool bPreserve = false );
void SetUseDoubleSystemFrameSize ( const bool bNDSFSize ) { bUseDoubleSystemFrameSize = bNDSFSize; }
virtual bool Put ( const CVector<uint8_t>& vecbyData, const int iInSize );
virtual bool Get ( CVector<uint8_t>& vecbyData, const int iOutSize );
int GetAutoSetting() { return iCurAutoBufferSizeSetting; }
void GetErrorRates ( CVector<double>& vecErrRates, double& dLimit, double& dMaxUpLimit );
protected:
void UpdateAutoSetting();
void ResetInitCounter();
// statistic (do not use the vector class since the classes do not have
// appropriate copy constructor/operator)
CErrorRate ErrorRateStatistic[NUM_STAT_SIMULATION_BUFFERS];
CNetBuf SimulationBuffer[NUM_STAT_SIMULATION_BUFFERS];
int viBufSizesForSim[NUM_STAT_SIMULATION_BUFFERS];
double dCurIIRFilterResult;
int iCurDecidedResult;
int iInitCounter;
int iCurAutoBufferSizeSetting;
int iMaxStatisticCount;
bool bUseDoubleSystemFrameSize;
double dAutoFilt_WightUpNormal;
double dAutoFilt_WightDownNormal;
double dAutoFilt_WightUpFast;
double dAutoFilt_WightDownFast;
double dErrorRateBound;
double dUpMaxErrorBound;
};
// Conversion buffer (very simple buffer) --------------------------------------
// For this very simple buffer no wrap around mechanism is implemented. We
// assume here, that the applied buffers are an integer fraction of the total
// buffer size.
template<class TData>
class CConvBuf
{
public:
CConvBuf() { Init ( 0 ); }
void Init ( const int iNewMemSize, const bool bNUseSequenceNumber = false )
{
// allocate internal memory and reset read/write positions
vecMemory.Init ( iNewMemSize );
iMemSize = iNewMemSize;
iBufferSize = iNewMemSize;
bUseSequenceNumber = bNUseSequenceNumber;
Reset();
}
void Reset()
{
iPutPos = 0;
iGetPos = 0;
}
void SetBufferSize ( const int iNBSize )
{
// if buffer size has changed, apply new value and reset the buffer pointers
if ( ( iNBSize != iBufferSize ) && ( iNBSize <= iMemSize ) )
{
iBufferSize = iNBSize;
Reset();
}
}
void PutAll ( const CVector<TData>& vecsData )
{
iGetPos = 0;
std::copy ( vecsData.begin(),
vecsData.begin() + iBufferSize, // note that input vector might be larger then memory size
vecMemory.begin() );
}
bool Put ( const CVector<TData>& vecData, const int iVecSize, const TData SequenceNumber = 0 )
{
// calculate the end position after copying
int iEnd = iPutPos + iVecSize;
// consider optional sequence number
if ( bUseSequenceNumber )
{
iEnd++;
}
// first check for buffer overrun
if ( iEnd <= iBufferSize )
{
// copy new data in internal buffer
std::copy ( vecData.begin(), vecData.begin() + iVecSize, vecMemory.begin() + iPutPos );
// add optional sequence number (NOTE that we currently
// only support a single sequence number per packet)
if ( bUseSequenceNumber )
{
// append the sequence number at the end
vecMemory[iPutPos + iVecSize] = SequenceNumber;
}
// set buffer pointer one block further
iPutPos = iEnd;
// return "buffer is ready for readout" flag
return ( iEnd == iBufferSize );
}
// buffer overrun or not initialized, return "not ready"
return false;
}
const CVector<TData>& GetAll()
{
iPutPos = 0;
return vecMemory;
}
void GetAll ( CVector<TData>& vecsData, const int iVecSize )
{
iPutPos = 0;
// copy data from internal buffer in given buffer
std::copy ( vecMemory.begin(), vecMemory.begin() + iVecSize, vecsData.begin() );
}
bool Get ( CVector<TData>& vecsData, const int iVecSize )
{
// calculate the input size and the end position after copying
const int iEnd = iGetPos + iVecSize;
// first check for buffer underrun
if ( iEnd <= iBufferSize )
{
// copy new data from internal buffer
std::copy ( vecMemory.begin() + iGetPos, vecMemory.begin() + iGetPos + iVecSize, vecsData.begin() );
// set buffer pointer one block further
iGetPos = iEnd;
// return the memory could be read
return true;
}
// return that no memory could be read
return false;
}
protected:
CVector<TData> vecMemory;
int iMemSize;
int iBufferSize;
bool bUseSequenceNumber;
int iPutPos, iGetPos;
};