Feature #4517

SAT>IP: Improve the TCP transport

Added by Mono Polimorph 17 days ago. Updated 13 days ago.

Status:NewStart date:2017-08-03
Priority:NormalDue date:
Assignee:Jaroslav Kysela% Done:

0%

Category:SAT>IP
Target version:-

Description

Hi,

I'm working to improve the TCP transport. And this is a continuation of the issue #4226. So I appreciate a feedback for my ideas:

- The first point is adjust the size of RTP 'chunks' to the TCP_PAYLOAD 'chunks'. Now, RTP_TCP_PAYLOAD=(87*188+12+4)=16,372 bytes; and RTP_BUFSIZE=(256*1024)=262,144 bytes. So it's impossible to write one RTP chunk with only one call in the TCP socket.

- The second point is to improve the write in the socket to the 'chunks' boundaries. In the function "rtp.c@satip_rtp_tcp_data()" will be necessary to repeat the call to "tvh_write()" if the written length is less than the chunk's size.

- The third idea is add some kind of intelligent packets discarding. If the buffer of the socket is completely full, then is required to discard some packets. My initial idea is remove one full RTP chunk, but I'm not sure if this is the best option.

Please, can you comment your opinion?
Thank you!

History

#1 Updated by Jaroslav Kysela 17 days ago

The first point is adjust the size of RTP 'chunks' to the TCP_PAYLOAD 'chunks'. Now, RTP_TCP_PAYLOAD=(87*188+12+4)=16,372 bytes; and RTP_BUFSIZE=(256*1024)=262,144 bytes. So it's impossible to write one RTP chunk with only one call in the TCP socket.

16372 < 262144, so you can write about 16 chunks to the kernel's buffer

The second point is to improve the write in the socket to the 'chunks' boundaries. In the function "rtp.c@satip_rtp_tcp_data()" will be necessary to repeat the call to "tvh_write()" if the written length is less than the chunk's size.
The third idea is add some kind of intelligent packets discarding. If the buffer of the socket is completely full, then is required to discard some packets. My initial idea is remove one full RTP chunk, but I'm not sure if this is the best option.

Yes, non-blocking I/O should be used and the data should be queued and/or destroyed later when the socket has no room for new data after some time. But RTSP code might write to the socket, too. The both 'senders' must write/queue in sync.

#2 Updated by Mono Polimorph 17 days ago

Hi,

Jaroslav Kysela wrote:

The first point is adjust the size of RTP 'chunks' to the TCP_PAYLOAD 'chunks'. Now, RTP_TCP_PAYLOAD=(87*188+12+4)=16,372 bytes; and RTP_BUFSIZE=(256*1024)=262,144 bytes. So it's impossible to write one RTP chunk with only one call in the TCP socket.

16372 < 262144, so you can write about 16 chunks to the kernel's buffer

Maybe I've misinterpreted the code. The RTP_TCP_PAYLOAD defines the maximum size of an interlaved chunk over the TCP socket. And the RTP_BUFSIZE is the size of the TS packets (188*N) in memory. Then, how much data you try to write? I had imagined it was the equivalent of the buffer size. And if this is true then 266144 > 16372, so you need to write 16 times to the socket to complete one write!

Jaroslav Kysela wrote:

The second point is to improve the write in the socket to the 'chunks' boundaries. In the function "rtp.c@satip_rtp_tcp_data()" will be necessary to repeat the call to "tvh_write()" if the written length is less than the chunk's size.
The third idea is add some kind of intelligent packets discarding. If the buffer of the socket is completely full, then is required to discard some packets. My initial idea is remove one full RTP chunk, but I'm not sure if this is the best option.

Yes, non-blocking I/O should be used and the data should be queued and/or destroyed later when the socket has no room for new data after some time. But RTSP code might write to the socket, too. The both 'senders' must write/queue in sync.

The first problem isn't the interlave mode. The RTSP code can write when a stream chunk is completed. It's only required to put some priorities: RTSP has maximum priority, stream=0 (RTP) has the lower priority, and stream=1 (RTCP) has a medium priority.

Futhermore, when in streaming no RTSP commands are sended by the server. So, the problem when the stream is stalled because a socket buffer fully is not related to the priorities. Only some data needs to be discarded.

So, you agree to implement the priorities first?

#3 Updated by Jaroslav Kysela 17 days ago

Mono Polimorph wrote:

Hi,

Jaroslav Kysela wrote:

The first point is adjust the size of RTP 'chunks' to the TCP_PAYLOAD 'chunks'. Now, RTP_TCP_PAYLOAD=(87*188+12+4)=16,372 bytes; and RTP_BUFSIZE=(256*1024)=262,144 bytes. So it's impossible to write one RTP chunk with only one call in the TCP socket.

16372 < 262144, so you can write about 16 chunks to the kernel's buffer

Maybe I've misinterpreted the code. The RTP_TCP_PAYLOAD defines the maximum size of an interlaved chunk over the TCP socket. And the RTP_BUFSIZE is the size of the TS packets (188*N) in memory. Then, how much data you try to write? I had imagined it was the equivalent of the buffer size. And if this is true then 266144 > 16372, so you need to write 16 times to the socket to complete one write!

OK, I made also mistake, to clarify: RTP_BUFSIZE is used only for UDP and it defines the in-kernel buffer for UDP packets. The default TCP buffer size can be obtained using 'cat /proc/sys/net/ipv4/tcp_wmem' - second value. TVH does not change this buffer size through SO_SNDBUF at the time - we should probably do it.

#4 Updated by Mono Polimorph 17 days ago

Jaroslav Kysela wrote:

OK, I made also mistake, to clarify: RTP_BUFSIZE is used only for UDP and it defines the in-kernel buffer for UDP packets. The default TCP buffer size can be obtained using 'cat /proc/sys/net/ipv4/tcp_wmem' - second value. TVH does not change this buffer size through SO_SNDBUF at the time - we should probably do it.

In my server this value is by default '16384' just 12 bytes less than the RTP_TCP_PAYLOAD.
I'll do some testing increasing this value at system level. However, I suggest you to change the TCP buffer size with the sockopt SO_SNDBUF when use RTP_over_TCP.

But in any case, some logic for discarding data from the buffer when it's full for some time, instead of stop the stream, will be necessary.

Thank you for your support!

#5 Updated by Mono Polimorph 17 days ago

Hi,

I think I have discovered the problem! :)

The TCP connection is stalled just after 30 seconds of play. You can try to show any program and with any condition, that after just 30 seconds the connection in the "master" (remote) server is expired! This only appears with Interlaved RTP over TCP.

The message log in the master server is:

8A075BF8/52: session closed (timeout)

Then the question is: Where is the problem, in the SAT>IP client part or in the SAT>IP server part?

A TCPdump indicates that using the Interlaved RTP over TCP, after the PLAY command it's sended a keepalive OPTIONS command (with the corresponding response) just after 15 seconds. But after another 15 seconds no new OPTIONS appears... just the stream is stoped. Perhaps the problem is in the client...

#6 Updated by Mono Polimorph 16 days ago

Hi,

I think the problem is in the server part.

I do this test:

- Using one SAT>IP client, tune one radio in a MUX with more than one radio program (a radio has a low bitrate, compatible with a tcpdump of the Interlaved RTP stream).
- After 10 seconds change to a different radio channel in the same MUX.
- After another 10 seconds change to the first radio.
- After 8 seconds rechange to another radio... just at 28 seconds of total.
- At second 30'' the stream stops... even if the PLAY commands are send and confirmed!

So, the problem isn't the client part. It's the sever part that doesn't reset the timer.

#7 Updated by Mono Polimorph 16 days ago

Hi,

I solved this problem! ;)

Here the patch:

---
 src/satip/rtsp.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/satip/rtsp.c b/src/satip/rtsp.c
index d71c502..236c68b 100644
--- a/src/satip/rtsp.c
+++ b/src/satip/rtsp.c
@@ -237,7 +237,7 @@ rtsp_session_timer_cb(void *aux)
 static inline void
 rtsp_rearm_session_timer(session_t *rs)
 {
-  if (!rs->shutdown_on_close) {
+  if ((!rs->shutdown_on_close) || (rs->rtp_peer_port == RTSP_TCP_DATA)) {
     pthread_mutex_lock(&global_lock);
     mtimer_arm_rel(&rs->timer, rtsp_session_timer_cb, rs, sec2mono(RTSP_TIMEOUT));
     pthread_mutex_unlock(&global_lock);
--
1.7.10.4

As you can see, the problem is that the server doesn't rearm the RTP thread when using Interlaved RTP over TCP.

Please, commit this patch!

Also available in: Atom PDF