Skip to content

Using Reopen() to flush built-up readBuffer#576

Merged
alexlivekit merged 3 commits intomainfrom
alexmigolin/tel-322-ignore-early-packets-for-outbound-calls
Feb 6, 2026
Merged

Using Reopen() to flush built-up readBuffer#576
alexlivekit merged 3 commits intomainfrom
alexmigolin/tel-322-ignore-early-packets-for-outbound-calls

Conversation

@alexlivekit
Copy link
Copy Markdown
Contributor

@alexlivekit alexlivekit commented Jan 27, 2026

From initial PR, timeline:

  • Start outbound call.
    • This causes us first create a local UDP socket to reserve the port.
    • rtpLoop is not yet started, only after accepting call (meaning we're not reading from socket at all)
    • This is a good behavior, since we want media to be ready asap.
    • Send RTP offer.
  • Remote side receives RTP offer, generates RTP answer and sends back.
    • This can be with either SIP-183 or SIP-200.
    • On a 200, there is no issue.
    • On a 183 code, the remote media stack starts sending RTP to local cloud-sip right away.
  • As long as the call is not answered
    • Remote end is sending RTP.
    • Local end not reading RTP from OS socket.
    • UDP buffer accumulates packets.
    • If UDP buffer is maxed, new packets arriving to the machine will be dropped.
  • Call is accepted
    • Only now do we start rtpLoop
    • OS UDP buffer has data, and if it was full can potentially have bot a lot of it, and the moment we start reading, it will suddenly accept new RTP packets creating a discontinuity. Data shows it can be in the range of 0.5 to 1 seconds.

This PR is here to address that issue.

Comment thread pkg/sip/media_port.go Outdated
// Creates a new underlying UDP connection on the same port.
// The practical use of this function is to discard the assicuated OS-level read buffer of the old socket.
func (c *udpConn) Reopen() error {
lc := &net.ListenConfig{
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is possible to enable SO_REUSEADDR here, instead of on creation, but would require an entire rework of these interface chains. Avoiding that for now.

@alexlivekit alexlivekit marked this pull request as ready for review January 27, 2026 08:01
@alexlivekit alexlivekit requested a review from a team as a code owner January 27, 2026 08:01
Comment thread pkg/sip/media_port.go Outdated
lc := &net.ListenConfig{
Control: func(network, address string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) {
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, anything that has to do with syscall should be in a separate file, under a build flag. This also implies that there should be a file that provides a fallback if these syscalls are not available.

So maybe we could solve it a bit more naively to avoid these portability issues? For example, we could just run the read loop on creation, but do not pass packets down until the port is explicitly enabled.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could just run the read loop on creation

That would have been ideal, and was my first go-to approach. But sure to how things are structured right now, we can one of the following:

  1. This PR or a variation (no reopen, just straight up close and immediately open on the same port).
  2. Start a "custom" rtp loop - just read & discard function until told to stop. Not reusing the Session type.
  3. Start a dummy Session type, have it run the normal, then, when we receive the answer SDP (and thus have *MediaConf), we can determine whether its srtp.NewSession(p.log, p.port, c.Crypto) or rtp.NewSession(p.log, p.port) and drop the old session.
  4. Ideally, I'd like to be able to start the normal session without knowing the selected codecs/crypto just yet, but that requires quite a lot of changes that I'm not sure need to be taken on today.
    All these aren't great to some extent. I think option 2 is easy enough as well, but I'd like to avoid 3.

Do you have any specific preferences on this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexlivekit I'm probably missing something important that makes it harder to do so, but what if we just run rtpLoop in MediaPort on port creation? This will automatically run rtpReadLoop, which will start consuming packets. However, until MediaPort.hnd is not set it will drop them immediately. So we can make it only enable that handler after we SetConfig. That should work, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need the session for that, and you need the config for the session. So:
SDP answer -> config -> sessoin -> rtploop.
To change this I'd need to rewire quite a bit, hence opting not to.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yeah, you are right, I missed that part. Lets go with your proposed option 2. But please push it here first, there are some comments there. For example, rename stop to discard, and wait for the discard loop to stop before starting a real read loop.

Copy link
Copy Markdown
Contributor Author

@alexlivekit alexlivekit Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

The main problem with this approach imo is if we do DTLS with carriers, this may eat up server hello messages, delaying media establishment until the call is actually answered.

Edit: Never mind, this doesn't happen, as we do not emit the client hello until after setting the SDP answer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That shouldn't be a problem, since we don't use DTLS, we use SRTP only. It doesn't have hello messages, I think.

@alexlivekit alexlivekit force-pushed the alexmigolin/tel-322-ignore-early-packets-for-outbound-calls branch from 6edcc87 to 068b4d1 Compare February 6, 2026 08:22
Comment thread pkg/sip/media_port.go Outdated
@alexlivekit alexlivekit merged commit da622f7 into main Feb 6, 2026
5 checks passed
@alexlivekit alexlivekit deleted the alexmigolin/tel-322-ignore-early-packets-for-outbound-calls branch February 6, 2026 18:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants