public int calculateBufferSize(long totalBufferSizeInBytes, int totalBuffers) {
        checkArgument(totalBufferSizeInBytes >= 0, "Size of buffer should be non negative");
        checkArgument(totalBuffers > 0, "Number of buffers should be positive");

        // Since the result value is always limited by max buffer size while the instant value is
        // potentially unlimited. It can lead to an instant change from min to max value in case
        // when the instant value is significantly larger than the possible max value.
        // The solution is to limit the instant buffer size by twice of current buffer size in order
        // to have the same growth and shrink speeds. for example if the instant value is equal to 0
        // and the current value is 16000 we can decrease it at maximum by 1600(suppose alfa=0.1) .
        // The idea is to allow increase and decrease size by the same number. So if the instant
        // value would be large(for example 100000) it will be possible to increase the current
        // value by 1600(the same as decreasing) because the limit will be 2 * currentValue = 32000.
        // Example of change speed:
        // growing = 32768, 29647, 26823, 24268, 21956, 19864
        // shrinking = 19864, 21755, 23826, 26095, 28580, 31301, 32768
        long desirableBufferSize =
                Math.min(totalBufferSizeInBytes / totalBuffers, 2L * lastBufferSize);

        lastBufferSize += alpha * (desirableBufferSize - lastBufferSize);
        return lastBufferSize = Math.max(minBufferSize, Math.min(lastBufferSize, maxBufferSize));
    }
@Test
    void testCalculationBufferSize() {
        BufferSizeEMA calculator = new BufferSizeEMA(200, 10, 3);

        // The result value seeks to the bottom limit but it will take a while until it reaches it.
        assertThat(calculator.calculateBufferSize(111, 13)).isEqualTo(104);
        assertThat(calculator.calculateBufferSize(107, 7)).isEqualTo(59);
        assertThat(calculator.calculateBufferSize(107, 7)).isEqualTo(37);
        assertThat(calculator.calculateBufferSize(107, 7)).isEqualTo(26);
        assertThat(calculator.calculateBufferSize(107, 7)).isEqualTo(20);
        assertThat(calculator.calculateBufferSize(107, 7)).isEqualTo(17);
        assertThat(calculator.calculateBufferSize(107, 13)).isEqualTo(12);
        assertThat(calculator.calculateBufferSize(107, 13)).isEqualTo(10);

        // Upgrade
        assertThat(calculator.calculateBufferSize(333, 1)).isEqualTo(15);
        assertThat(calculator.calculateBufferSize(333, 1)).isEqualTo(22);
        assertThat(calculator.calculateBufferSize(333, 1)).isEqualTo(33);
        assertThat(calculator.calculateBufferSize(333, 1)).isEqualTo(49);
        assertThat(calculator.calculateBufferSize(333, 1)).isEqualTo(73);
        assertThat(calculator.calculateBufferSize(333, 1)).isEqualTo(109);
    }