Skip to content

Conversation

@alexlivekit
Copy link
Contributor

No description provided.

@alexlivekit alexlivekit requested a review from a team as a code owner January 22, 2026 01:11
p.stats.Streams.Add(1)
p.mediaReceived.Break()
log := p.log.WithValues("ssrc", ssrc)
log.Infow("accepting RTP stream")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved to include discarded packets number, and first RTP seq

// such as in outbound calls that take a sec to answer, we have a ton of junk in the stream.
// We need to discard all of it.
now := time.Now()
if lastPacketTime.IsZero() || now.Sub(lastPacketTime) < time.Millisecond {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note, for inbound calls, we will discard the first packet as well, even if there isn't anything buffered in there.
We can, of course introduce code to correct for that, but the added complexity was deemed not justified due to non-existing impact.

}
if catchup {
// When a remote writer has been sending data but the local stream didn't start the RTP loop,
// such as in outbound calls that take a sec to answer, we have a ton of junk in the stream.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure I'm following here.

There's presumably some garbage sent before the call is established. But the code in the PR doesn't even check the RTP headers or the payload. Why are we dropping it unconditionally?

Assuming there's some audio there (silence? ringing?) or even just audio junk, it won't propagate through the media pipeline until it's actually enabled (we have multiple SwitchWriters in the pipeline that can cut the stream).

So why is this necessary?

Copy link
Contributor Author

@alexlivekit alexlivekit Jan 26, 2026

Choose a reason for hiding this comment

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

The timeline is this:

  • Start outbound call.
    • This causes us to start configuring the media port, and bind local sockets.
    • However, we do not yet start rtpLoop.
    • We want to be doing as early as possible to make sure media i ready to go. If we ever add DTLS support for calls, it would be cruicial for this to happen early as possible to give the encryption time to set up.
  • Wait for user to answer
    • During this time, incoming packets that are already being sent by the callee to livekit are just sitting in the OS UDP buffer.
    • Some packets will be dropped from the buffer. Annoyingly, it will be newer packets that would be dropped by the OS if the UDP buffer is full.
  • Receive SIP-200
  • Only now do we start rtpLoop
  • This starts reading ALL the packets in the OS buffer, along with any gaps that might have been in there due to packet drops.

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.

3 participants