Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can i configure srt socket without loss #1579

Closed
byrcoder opened this issue Sep 27, 2020 · 19 comments
Closed

How can i configure srt socket without loss #1579

byrcoder opened this issue Sep 27, 2020 · 19 comments
Assignees
Labels
Type: Question Questions or things that require clarification

Comments

@byrcoder
Copy link

Hi,
I am trying to make srt as a tcp proxy which should make sure no packet loss allowed.
the srt config code as following:

drop = false;
tspd = false;
srt_setsockflag(fd, SRTO_TLPKTDROP, &drop, sizeof(drop));
srt_setsockflag(fd, SRTO_TSBPDMODE, &tspd, sizeof(tspd));

when I check the byte from the srt proxy, somehow the data loss sometimes. Do you have any ideas of what is causing this ?

@byrcoder byrcoder added the Type: Question Questions or things that require clarification label Sep 27, 2020
@byrcoder
Copy link
Author

I have some log like this. It seems that the flag works on.

src/srtcore/core.cpp l=2744 area=processSrtMsg_HSRSP msg=: HSRSP/rcv: Ve
rsion: 1.4.1 Flags: SND:000000B4 (-TSBPD-snd -TSBPD-rcv +haicrypt -TLPktDrop +NAKReport +ReXmitFlag -StreamAPI +unknown)

@ethouris
Copy link
Collaborator

For that you better use the file mode. There are multiple options that are affected, so you better use the SRTO_TRANSTYPE option.

Also, for TCP proxying you have also an application: srt-tunnel.

@byrcoder
Copy link
Author

For that you better use the file mode. There are multiple options that are affected, so you better use the SRTO_TRANSTYPE option.

Also, for TCP proxying you have also an application: srt-tunnel.

Thanks for the suggestions. I wander the only diff between file mode and live mode is the initialize configure for drop message. What can i do if I have to use live mode ?

@ethouris
Copy link
Collaborator

No. The following options are affected by SRTO_TRANSTYPE (using short names):

  • tsbpdmode
  • rcvlatency and peerlatency
  • tlpktdrop and snddropdelay
  • messageapi
  • nakreport
  • payloadsize
  • linger

What's exactly your use case? For me, making a TCP proxy by using the SRT live mode doesn't make any sense, or at least a solution that relies here on blindly transferring the data between two TCP endpoints won't work correctly with live mode.

@byrcoder
Copy link
Author

I have a test like this:

  1. recv_from_tcp
  2. srt_send
  3. tcp close
  4. srt_close
    I read the code again . The data will not actual send because the live mode has no linger off.
    Then I open the linger off again in live mode, the data still loss.

The other options (nakreport, payloadsize) I have not read about. I will test later.

@ethouris
Copy link
Collaborator

I can only recommend that you read the sources of the applications (srt-test-file, srt-file-transmit and first of all srt-tunnel) and examples (sendfile, recvfile).

@byrcoder
Copy link
Author

No. The following options are affected by SRTO_TRANSTYPE (using short names):

  • tsbpdmode
  • rcvlatency and peerlatency
  • tlpktdrop and snddropdelay
  • messageapi
  • nakreport
  • payloadsize
  • linger

What's exactly your use case? For me, making a TCP proxy by using the SRT live mode doesn't make any sense, or at least a solution that relies here on blindly transferring the data between two TCP endpoints won't work correctly with live mode.

HI, I have the test about the options in livecc. I close tsbpdmode , nakreport and set linger like file mode. The only different opt is messageapi that is true. As I cannot set messageapi false with livecc mode. The test result shows loss packet. It seems that livecc cannot work as file mode. Do you have any ideas of what is causing this ?

By the way I wanna use live mode as it works well for low latency.

@maxsharabayko
Copy link
Collaborator

Hi @byrcoder

The test result shows loss packet.

Please define how do you measure the loss? Do you use SRT statistics or your own?

Please note that in SRT if a packet is lost, it is then retransmitted until delivered or until it is decided to be dropped due to latency constraints. Refer to pktRcvDropTotal and pktRcvLossTotal.

You also should disable TL Packdet Drop to prohibit SRT to drop packets.

Also you should no close the connection (srt_close) untill all data is delivered. Linger can help. But you can also check it on your own using srt_getsndbuffer(..). See how it is used in srt-file-transmit.

@ethouris
Copy link
Collaborator

The live mode has several restrictions:

  • the maximum single-sending instruction may contain up to the value of payloadsize, default is 1316 and can be only enlarged to 1456.
  • this one sending call will define a single data portion with assigned schedule time. The time distance when the packet is ready to retrieve at the receiver side will be replayed basing on that time.

This means that the stream you are sending over SRT in live mode should be already a live stream, that is, time distances between consecutive packets should be more-less even with very little tolerance. If you are reading the data on-the-fly from a TCP connection, you should have also some intermediate module that will make sure that times between consecutive packets are even.

You can turn off conditional dropping of the packets by turning off tlpktdrop option, although this may cause that a fallback for a situation that the packet isn't recovered on time, with tolerance given by the latency, the whole stream might be paused instead and potentially challenge the receiver buffer.

Delivery times of a stream received over TCP isn't something you can rely on, as it prefers reliability over timely delivery and may introduce unnecessary delays. SRT in live mode differs to it mainly in that it doesn't do any sending speed control, except for the overhead, if configured.

@byrcoder
Copy link
Author

byrcoder commented Oct 14, 2020

Hi @byrcoder

The test result shows loss packet.

Please define how do you measure the loss? Do you use SRT statistics or your own?

Please note that in SRT if a packet is lost, it is then retransmitted until delivered or until it is decided to be dropped due to latency constraints. Refer to pktRcvDropTotal and pktRcvLossTotal.

You also should disable TL Packdet Drop to prohibit SRT to drop packets.

Also you should no close the connection (srt_close) untill all data is delivered. Linger can help. But you can also check it on your own using srt_getsndbuffer(..). See how it is used in srt-file-transmit.

Do you use SRT statistics or your own?
Yes, I check the content of the downloading myself. Which Is not the same from the server with live mode.And the file is endless like a live stream with special format That I can check.
By the way, It work fine with file mode.

Please define how do you measure the loss?
I compare the file in server and the client download by srt. The content is diff. This happens in 200 tcp qps. And the data loss with some srt-connections not all. But as time goes on, the error-connections incs. The test last for at least 4 hours.
And the test works well in file mode which last for days.

@byrcoder
Copy link
Author

The live mode has several restrictions:

  • the maximum single-sending instruction may contain up to the value of payloadsize, default is 1316 and can be only enlarged to 1456.
  • this one sending call will define a single data portion with assigned schedule time. The time distance when the packet is ready to retrieve at the receiver side will be replayed basing on that time.

This means that the stream you are sending over SRT in live mode should be already a live stream, that is, time distances between consecutive packets should be more-less even with very little tolerance. If you are reading the data on-the-fly from a TCP connection, you should have also some intermediate module that will make sure that times between consecutive packets are even.

You can turn off conditional dropping of the packets by turning off tlpktdrop option, although this may cause that a fallback for a situation that the packet isn't recovered on time, with tolerance given by the latency, the whole stream might be paused instead and potentially challenge the receiver buffer.

Delivery times of a stream received over TCP isn't something you can rely on, as it prefers reliability over timely delivery and may introduce unnecessary delays. SRT in live mode differs to it mainly in that it doesn't do any sending speed control, except for the overhead, if configured.

time distances between consecutive packets should be more-less even with very little tolerance.

Yes, the test tcp works as a live stream. The data will recv with tcp endless unless srt send buffer full. When the srt full the tcp will not read util it is ok for srt sending.

I had turned off the tlpktdrop option. And it is expected that pausing the connection when srt send stop or the srt buffer is full.

@mbakholdina mbakholdina added this to the v1.5.0 milestone Oct 14, 2020
@ethouris
Copy link
Collaborator

I'm not exactly following you.

Please describe again your configuration. Do you have data transfer from SRT to TCP only, or from TCP to SRT as well?

If you have a case of reading from TCP and sending these data over SRT, then you need some intermediate buffer that will be filled all the time whenever data come over TCP. A separate procedure should read from this buffer by portions of maximum 1316 bytes (by default - this size can be increased upto 1456 by SRTO_PAYLOADSIZE option) and send them using srt_sendmsg function, making sure that there's a relatively constant time interval between the calls of this function (you have to call usleep or something like that if needed), and this time interval must be defined the way that would make the sending speed identical with your stream bitrate.

If you are talking about having the SRT sender buffer full, then there's something wrong because this shall not happen in live mode. The sender buffer in SRT plays actually two roles:

  1. Allows to separate the API call of the sending function from the physical sending the packet over UDP socket.
  2. Keeps packets that were sent, but not acknowledged, for the need of prospective retransmission.

Both these features have also their assigned sizes:

  1. Schedule window - it's the distance between the packet that was last scheduled (using srt_send* functions) and last sent over the UDP socket
  2. Flight window - it's the distance between the last packet sent over UDP socket and the oldest packet still not acknowledged

So, in File mode the value of Schedule Window may grow up to the value of buffer capacity decreased by the Flight Window.

In Live mode, however, the Schedule Window shall be mostly constantly 1, at worst 2, and only exceptionally it may grow a little bit more in case when you had lately quite a large portion of lost packets that have to be retransmitted, and have configured a bandwidth limit on the socket - this way, the regular packets will be extra delayed, so the Schedule Window may temporarily grow. As the flight window is usually the size of about 1/10 of the sender buffer, then the situation when you make the SRT sender buffer full in live mode means simply that you are sending faster than your network allows - and the network will respond with packet drops.

In other words, the speed with which you are sending packets over SRT in live mode must be exactly the desired speed of sending the packets over the network - and not just average in general, but as an average counted for at most 16 packets (once per 16 packets there's a "packet pair" sent when two consecutive packets are sent without any delay between them, which is the part of the procedure measuring the upper bandwidth limit).

Let's state you send packets (or, say, "portions of data") of 1316 bytes using srt_sendmsg and let's define the time when this call has happened for the first of them as T1 and the 16th of them as T16.

In this case the value calculated as 1613168/(T16-T1) must result equal to your current live stream bitrate. This must hold true for any range of packets, also with range of only 4 packets.

That's the exact thing being the difference between File and Live mode. In File mode you can call srt_sendmsg function for every packet without any delay between the calls (as well as you may pass a bigger buffer than even 1456 bytes - data will be split into single packets) - packets will be stored in the buffer and then sent with the speed that has been measured as currently best available in the network. In Live mode there's no speed measurement made and packets are being sent on the network immediately after you schedule them, no matter if the speed can be withstood by the network, or could result with packet drops. If a delay between consecutive packets is needed, it's the application who should do "sleeps" between the calls of srt_sendmsg for consecutive packets.

@maxsharabayko maxsharabayko modified the milestones: v1.5.0, v1.4.3 Oct 22, 2020
@byrcoder
Copy link
Author

Thanks for your detailed answer.

The data transfer from TCP-Server to SRT-Server. The TCP-Server and SRT-Server works as follow:

  1. TCP-Server receive the data and send to SRT-Server
  2. SRT-Server receive the data and store the data

The simple code shows as follow:

// srt config client and server both have the same config
create_srt_fd()
{
    fd  = srt_create_socket()
    // srt config
    (SRTO_RCVSYN, false)
    (SRTO_SNDSYN, false)
    (SRTO_TSBPDMODE, false)
    (SRTO_TLPKTDROP, false)
    (SRTO_LINGER, 30s)
}

srt_read(fd, buf, nbyte, nread)
{
    while((ret = srt_recv(fd, buf, nbyte)) == SRT_ERROR) {
        if(st_srt_again(eno)) {
            srt_epoll(fd)
        }
        else {
            return ret
        }
    }
    if(ret <= 0) {
        return SRT_ERROR
    }

    nread = ret;
    return error_success
}


srt_write(fd, buf, nbyte)
{
    ret = error_success
    has_send = 0

    while(has_send < nbyte) {
        size_t next_send = nbyte - has_send;
        if(next_send > SRT_LIVE_DEF_PLSIZE) {
            next_send = SRT_LIVE_DEF_PLSIZE;
        }
        while ((ret = srt_send(fd, buf+has_send, next_send)) == SRT_ERROR) {
            if (srt_again(eno)) {
                srt_epoll(fd)
            } else {
                return ret;
            }
        }
        has_send += ret;
    }
    return error_success;
}


// The TCP-SERVER work as following:

main_loop_tcp_to_srt()
{
    buf[2048];
    {
        ...
        len = tcp_read(tcp_fd, buf, 2048);
        check_or_exit(len)
        srt_write(srt_fd, buf, len); // srt_write block util srt_write success
        ...
    } loop
}

// The SRT-SERVER works as following:

main_loop_srt_read()
{
    buf[2048]
    {
        len = srt_read(srt_fd, buf, 2048)
        check_or_exit(len)
        store(buf, len)  // the data which store check error
    } loop
}

So The maximum length of the intermediate buffer is 2048 bytes. As the tcp input is a live stream something like rtmp,
the time interval should be almost constant. I don't think I should estimate the interval time which is a tough job.

Event though the loss happens, Why wouldn't the retransmission work for srt in live mode?
I know the sender will drop the buffer if the option of TSBP set, so I close the option (as the function create_srt_fd above). I think the loss packet would hold by the sender buffer unless the ack of the packet has been received. This question bothers me a lot.

@mbakholdina mbakholdina removed this from the v1.4.3 milestone Oct 23, 2020
@ethouris
Copy link
Collaborator

Here is exactly the problem:

 while ((ret = srt_send(fd, buf+has_send, next_send)) == SRT_ERROR) 

This means that when you send 2048 bytes from the live TCP stream at once, then you'd call srt_send twice without a delay between them. OTOH you are setting TSBPD mode to false, so in this case it will work in message mode (the exact size of buffer will be retrieved at the receiver side).

Maintaining delays between calls to srt_send is mandatory in live mode, as in this mode no speed control is being done nor any kind of "smoothing" the sending process (this is because simply SRT cannot do this because the delays should be calculated basing on the timestamps in the video and audio frames from the mpeg-ts stream).

OTOH if it so, as you said, that you are sending this over SRT to archive it, and moreover you are setting TSBPD mode off, which means that timing isn't important for your transmission, I still think that "file mode" is exactly what you need. So first of all you need this option:

int tt = SRTT_FILE;
srt_setsockflag(socket, SRTO_TRANSTYPE, &tt, sizeof tt);

This also takes care of TLPKTDROP and TSBPDMODE options the same way as you set them, so you can remove these from the list. Note that also by setting this value sets also SRTO_MESSAGEAPI to false, which means stream mode, just like in TCP.

I also think that you are trying to do something similar as the srt-tunnel application does. You can try this out and see if this does what you expect to have.

@byrcoder
Copy link
Author

byrcoder commented Oct 27, 2020

Yes, file mode is ok. But the test shows the file mode has two problems:

  1. When loss event happens at the very beginning of the slow-start state, the sending speed is very low. I think the the minimal value of the follow-window should be set and the slow-start mustn't stop before the minimal value.
  2. The test shows that it will takes a long time when the network recover from high packet-loss.(The test shows as following)

So. We wanna a better mechanism something like live mode.

image

@ethouris
Copy link
Collaborator

Ok, but in order to use the live mode you'd have to keep the bitrate at the same level as the bitrate of the TCP stream, and implement this yourself by calling srt_send function at appropriate time. You might also need to define an appropriate payload size (you can set also SRTO_PAYLOADSIZE to 1456) and send exactly that amount of data at once (also by extracting exactly that number of bytes from the intermediate buffer that you fill by reading from TCP). Might even be that you simply read the data in 1456-byte chunks from the TCP medium (TCP doesn't mandate you the size of the single unit, right?) and then pass this directly to SRT. If you are sure that the stream in TCP is really a live stream and therefore it comes in in a constant bitrate (you might also want to add some latency in reading TCP so that you can compensate any delays if they happen in TCP by this latency by sending faster when TCP is momentarily slower).

In this case you might want to have TSBPDMODE=off, TLPKTDROP=off, NAKREPORT=on and PAYLOADSIZE=1456. Just remember that the ::read function that reads from TCP must also request 1456 bytes of data.

@maxsharabayko
Copy link
Collaborator

Hi @byrcoder
If you are testing file mode on Windows, the slow start will tend to fail due to a known issue #973 (the sender will ignore a failure in sending a packet -> the receiver will report a loss -> sender ends the "slow start" phase).
PR #974 was addressing it, but the work on it has been postponed.

@byrcoder
Copy link
Author

byrcoder commented Nov 2, 2020

Hi @byrcoder
If you are testing file mode on Windows, the slow start will tend to fail due to a known issue #973 (the sender will ignore a failure in sending a packet -> the receiver will report a loss -> sender ends the "slow start" phase).
PR #974 was addressing it, but the work on it has been postponed.

Thanks. My test is on linux.

@byrcoder byrcoder closed this as completed Nov 2, 2020
@byrcoder
Copy link
Author

byrcoder commented Nov 2, 2020

Ok, but in order to use the live mode you'd have to keep the bitrate at the same level as the bitrate of the TCP stream, and implement this yourself by calling srt_send function at appropriate time. You might also need to define an appropriate payload size (you can set also SRTO_PAYLOADSIZE to 1456) and send exactly that amount of data at once (also by extracting exactly that number of bytes from the intermediate buffer that you fill by reading from TCP). Might even be that you simply read the data in 1456-byte chunks from the TCP medium (TCP doesn't mandate you the size of the single unit, right?) and then pass this directly to SRT. If you are sure that the stream in TCP is really a live stream and therefore it comes in in a constant bitrate (you might also want to add some latency in reading TCP so that you can compensate any delays if they happen in TCP by this latency by sending faster when TCP is momentarily slower).

In this case you might want to have TSBPDMODE=off, TLPKTDROP=off, NAKREPORT=on and PAYLOADSIZE=1456. Just remember that the ::read function that reads from TCP must also request 1456 bytes of data.

It is unreasonable if I must implement srt_send myself. We will consider the file mode.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Question Questions or things that require clarification
Projects
None yet
Development

No branches or pull requests

4 participants