srt icon indicating copy to clipboard operation
srt copied to clipboard

Inconsistency in guidelines for Receiver buffer size

Open ivan94fi opened this issue 8 months ago • 1 comments

Hi,

I am trying to wrap my head around the SRT parameters for streaming at high bitrates, maxbw, rcvbuf, fc and so forth. I read the most referenced issues, as #642, #703, #409 and others, as well as the Configuration Guidelines and the Socket options page.

I have some doubts but if necessary I will make other issues. For now I want to address two simple questions.

First, in Configuration Guidelines, under "Calculating Target Size in Packets", there are the following sentences: https://github.com/Haivision/srt/blob/952f9495246abc201bac55b8f9ad7409c0572423/docs/API/configuration-guidelines.md?plain=1#L55-L57 And this makes sense to me as we divide the stream bitrate by 8 to have bytes/s, then we multiply by the interval of time that we are interested in, that is RTT + latency, and finally divide by the payload size, to get the number of packets.

However, in the section "Summing Up" we find this function: https://github.com/Haivision/srt/blob/952f9495246abc201bac55b8f9ad7409c0572423/docs/API/configuration-guidelines.md?plain=1#L96-L103 Here the code is almost the same, except for the division by two applied to the RTT value. I think this is an error and should be corrected.

As for the calculation of FC in Socket Options I see this calculation for the suggested FC value:

FC = (bps / 8) × (RTTsec + latency_sec) / (MSS - 44)

which is identical to the first sample I reported above.

So, in conclusion is it correct to state that the formulas to calculate the recommended rcvbuf size and fc size are the following?

RCVBUF = (bps / 8) × (RTTsec / 2 + latency_sec) / (MSS - 44)
FC = (bps / 8) × (RTTsec + latency_sec) / (MSS - 44)

The second problem I have is that in the comment from @maxsharabayko in https://github.com/Haivision/srt/issues/703#issuecomment-495570496, I see that the bandwidth is marked ad being the link bandwidth. However every other reference I found is talking about the payload bandwidth. Is referencing the link bandwidth correct or it should be written payload bandwidth?

Thank you.

ivan94fi avatar May 13 '25 13:05 ivan94fi

I made a python script to calculate the recommended dimensions for maxbw, rcvbuf and fc given a certain stream bandwidth, latency and rtt.

import math

UDP_HEADER_SIZE = 8
IPV4_HEADER_SIZE = 20
SRT_HEADER_SIZE = 16
MSS_SIZE = 1500
UDP_IPV4_HEADER_SIZE = UDP_HEADER_SIZE + IPV4_HEADER_SIZE  # 28
SRT_UDP_IPV4_HEADER_SIZE = UDP_IPV4_HEADER_SIZE + SRT_HEADER_SIZE  # 44


def compute_target_rcvbuf_size(rtt_ms, bandwidth_bps, latency_ms):
    # Rcvbuf bytes value, based on rtt, bandwidth and latency
    rcvbuf_bytes_value = (bandwidth_bps / 8) * ((latency_ms + rtt_ms / 2) / 1000)

    # Divide bytes value for (1500 - 44) = 1456 to get number of packets
    rcvbuf_packets_value = rcvbuf_bytes_value / (MSS_SIZE - SRT_UDP_IPV4_HEADER_SIZE)

    # Multiply for 1500 - 28 = 1472
    # (because internally the value set in SRTO_RCVBUF is divided by this number when setting the option to get packets)
    target_rcvbuf_value = rcvbuf_packets_value * (MSS_SIZE - UDP_IPV4_HEADER_SIZE)

    return target_rcvbuf_value


def compute_target_fc_size(rtt_ms, bandwidth_bps, latency_ms):
    ## FC
    # fc bytes value, based on rtt, bandwidth and latency
    fc_bytes_value = (bandwidth_bps / 8) * ((latency_ms + rtt_ms) / 1000)

    # fc packets value
    target_fc_value = fc_bytes_value / (MSS_SIZE - SRT_UDP_IPV4_HEADER_SIZE)  # 1500 - 44 = 1456

    return target_fc_value


rtt_ms = 200  # ms
bandwidth_bps = 419430400  # 400 Mbps
latency_ms = 120  # ms

target_fc_value = compute_target_fc_size(rtt_ms, bandwidth_bps, latency_ms)
target_rcvbuf_value = compute_target_rcvbuf_size(rtt_ms, bandwidth_bps, latency_ms)

target_maxbw_value = 2 * bandwidth_bps

target_fc_value, target_rcvbuf_value, target_maxbw_value = (
    math.ceil(target_fc_value),
    math.ceil(target_rcvbuf_value),
    math.ceil(target_maxbw_value),
)

lines = [
    ("FC", f"{target_fc_value} packets / {target_fc_value * (MSS_SIZE - SRT_UDP_IPV4_HEADER_SIZE) / 1024 / 1024:.2f} MB", f"(default 25600 packets / {25600 * (MSS_SIZE - UDP_IPV4_HEADER_SIZE) / 1024 / 1024 * 8:.2f} MB)"),
    ("RCVBUF", f"{target_rcvbuf_value / 1024 / 1024:.2f} MB / {math.ceil(target_rcvbuf_value / (MSS_SIZE - UDP_IPV4_HEADER_SIZE))} packets", "(default 8192 packets / 11.5 MB)"),
    ("MAXBW", f"{target_maxbw_value} / {target_maxbw_value / 1024 / 1024:.2f} Mbps", "(default 1 Gbps)"),
]

for l in lines:
    print("\t".join(l))

print()
print(f"fc={target_fc_value}&rcvbuf={target_rcvbuf_value}&maxbw={target_maxbw_value}")

When using the parameters hardcoded in the script, that is rtt = 200 ms, bandwidth = 400 Mbps, latency = 120 ms, the resulting numbers are the following:

Param Calculated value Default value
FC 11523 packets / 16.00 MB (default 25600 packets / 287.50 MB)
RCVBUF 11.12 MB / 7922 packets (default 8192 packets / 11.5 MB)
MAXBW 838860800 / 800.00 Mbps (default 1 Gbps)

ivan94fi avatar May 14 '25 10:05 ivan94fi