forked from zillevdr/vdr-plugin-softhddevice-drm
-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathfilllevel.cpp
More file actions
92 lines (82 loc) · 2.64 KB
/
filllevel.cpp
File metadata and controls
92 lines (82 loc) · 2.64 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
// SPDX-License-Identifier: AGPL-3.0-or-later
/**
* @file filllevel.cpp
* Low-pass Filter for Audio Buffer Fill Level Measurement
*
* @license{AGPL-3.0-or-later}
*/
#include <algorithm>
#include "filllevel.h"
#include "logger.h"
/**
* Resets the filter state.
*/
void cBufferFillLevelLowPassFilter::Reset(void)
{
m_state = UNINITIALIZED;
m_bufferFillLevelFramesAvg = 0;
m_frameCounter = 0;
}
/**
* Resets the received and written frames counters.
*/
void cBufferFillLevelLowPassFilter::ResetFramesCounters(void)
{
m_receivedFrames = 0;
m_writtenToAlsaFrames = 0;
}
/**
* Updates the buffer fill level average.
*
* Calculates the current buffer fill level based on received frames,
* written frames, and the hardware buffer fill level.
* Applies a low-pass filter (exponential moving average) to smooth the value.
* This is necessary, because the packets coming from VDR have a few milliseconds jitter.
*
* Handles state transitions:
* - UNINITIALIZED -> SETTLING: Initializes the average and sets a faster alpha.
* - SETTLING -> SETTLED: After a duration, switches to a slower alpha and fixes the target value.
*
* @param hardwareBufferFillLevelFrames Current fill level reported by the hardware (ALSA)
*/
void cBufferFillLevelLowPassFilter::UpdateAvgBufferFillLevel(int hardwareBufferFillLevelFrames)
{
std::lock_guard<std::mutex> lock(m_mutex);
int bufferFillLevelFrames = m_receivedFrames - m_writtenToAlsaFrames + hardwareBufferFillLevelFrames;
m_bufferFillLevelFramesAvg = m_bufferFillLevelFramesAvg * (1 - m_floatingAverageAlpha) + bufferFillLevelFrames * m_floatingAverageAlpha;
switch (m_state) {
case UNINITIALIZED:
m_floatingAverageAlpha = FLOATING_AVERAGE_ALPHA_SETTLING;
m_bufferFillLevelFramesAvg = bufferFillLevelFrames; // init with current value to speed up settling
m_frameCounter = 0;
m_state = SETTLING;
break;
case SETTLING:
if (m_frameCounter++ >= SETTLING_DURATION_PACKETS) {
m_floatingAverageAlpha = FLOATING_AVERAGE_ALPHA_NORMAL;
// fixate the current buffer fill level as target value, but guarantee a minimum buffer size
m_bufferFillLevelFramesTargetValue = std::max((double)m_minBufferSizeFrames, m_bufferFillLevelFramesAvg);
m_state = SETTLED;
}
break;
case SETTLED:
// nothing
break;
}
}
/**
* Converts the filter state to a string representation.
*
* @param state The state to convert
*
* @return String representation of the state
*/
const char* cBufferFillLevelLowPassFilter::StateToString(State state)
{
switch(state) {
case UNINITIALIZED: return "UNINITIALIZED";
case SETTLING: return "SETTLING";
case SETTLED: return "SETTLED";
}
return "Unknown";
}