Skip to content

TEL-886: Media Port rework - #802

Open
alexlivekit wants to merge 13 commits into
mainfrom
tel-886/media-port
Open

TEL-886: Media Port rework#802
alexlivekit wants to merge 13 commits into
mainfrom
tel-886/media-port

Conversation

@alexlivekit

@alexlivekit alexlivekit commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

This change is intended to:

  • Have little functional differences between it an main.
    • the one known thing: Plug-in processor moved back to ingesting 48khz audio and returning 48khz audio.
  • Add interface for clarity.
  • Add machinery to support renegotiation, early media, hold, etc. All these are still disabled for now, but there.
  • Add tests.

@alexlivekit
alexlivekit requested a review from a team as a code owner August 20, 2026 19:20
devin-ai-integration[bot]

This comment was marked as resolved.

@alexlivekit

Copy link
Copy Markdown
Contributor Author

Huh, the race in CI is real, and is apparently a problem in media-sdk (yay zerocopy) that previous tests simply did not expose.
So... no regression compared to main.

@alexfish8

Copy link
Copy Markdown
Contributor

Huh, the race in CI is real, and is apparently a problem in media-sdk (yay zerocopy) that previous tests simply did not expose. So... no regression compared to main.

Will fix this in media-sdk.

devin-ai-integration[bot]

This comment was marked as resolved.

@alexlivekit alexlivekit mentioned this pull request Aug 21, 2026
Comment thread pkg/sip/inbound.go Outdated
Comment thread pkg/sip/inbound.go
Comment thread pkg/sip/inbound.go Outdated
Comment thread pkg/sip/media_pipeline.go Outdated
Comment thread pkg/sip/media_pipeline.go Outdated
Comment thread pkg/sip/media_pipeline.go Outdated
Comment thread pkg/sip/media_port.go
negotiated *sdp.MediaConfig

audioIn *msdk.WriteCloserSwitch[msdk.PCM16Sample] // SIP RTP -> LK PCM
audioOut *msdk.WriteCloserSwitch[msdk.PCM16Sample] // LK PCM -> SIP RTP

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.

Why these two are pointers, but the other two are not?

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.

ha, nice catch.
We want to initialize the audio ones with msdk.NewWriteCloserSwitch, so that's why they're pointers.
Why the other ones are not? No reason. Fixed.

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.

Aren't they safe to use as zero values?

Comment thread pkg/sip/media_port.go
return errors.New("unexpected local address change")
}

audioToPort := p.audioOut.Swap(nil) // either nil or no-op closer

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.

Maybe assert that it's the case during swap?

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.

Not sure I follow. Are you talking about something like:

audioToPort := p.audioOut.Swap(nil)
if audioToPort != nil {
  if _, ok := audioToPort.(msdk.writeCloser[x]); !ok {
    log.Errorw(...)
  }
}

?

The only thin that swaps these is the configure function itself, so I'm not sure what the benefit would be there.
The comment is there to explain why we don't close the popped value.

Comment thread pkg/sip/outbound.go
Comment thread pkg/sip/room.go

// WriteOutboundDTMFTo tells the room where to send DTMF to.
// Returns the previously-set writer (if one exists).
WriteOutboundDTMFTo(w msdk.WriteCloser[*livekit.SipDTMF]) msdk.WriteCloser[*livekit.SipDTMF]

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.

Any specific reason to use pointers in livekit.SipDTMF? It's a tiny payload, might as well just copy it around.

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.

I guess the thread safety is a good benefit of copying. Fair enough.

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.

WriteSample passes lock by value: github.com/livekit/protocol/livekit.SipDTMF contains google.golang.org/protobuf/runtime/protoimpl.MessageState contains sync.Mutex I guess this is one,

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.

Oh, right, it's a protobuf. Can we swap it for a non-proto struct? I remember we had races on proto structs before.

Base automatically changed from tel-886/prep to main August 21, 2026 16:42
@alexlivekit
alexlivekit force-pushed the tel-886/media-port branch 3 times, most recently from 47b61bd to 5ad9b22 Compare August 21, 2026 20:59
@alexfish8

Copy link
Copy Markdown
Contributor

Huh, the race in CI is real, and is apparently a problem in media-sdk (yay zerocopy) that previous tests simply did not expose. So... no regression compared to main.

Will fix this in media-sdk.

Fixed in media-sdk#81.

devin-ai-integration[bot]

This comment was marked as resolved.

Comment thread pkg/sip/inbound.go Outdated
Comment thread pkg/sip/inbound.go Outdated
Comment thread pkg/sip/inbound.go Outdated
Comment thread pkg/sip/outbound.go Outdated
Comment thread pkg/sip/outbound.go Outdated
Comment thread pkg/sip/room.go

// WriteOutboundDTMFTo tells the room where to send DTMF to.
// Returns the previously-set writer (if one exists).
WriteOutboundDTMFTo(w msdk.WriteCloser[*livekit.SipDTMF]) msdk.WriteCloser[*livekit.SipDTMF]

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.

Oh, right, it's a protobuf. Can we swap it for a non-proto struct? I remember we had races on proto structs before.

Comment thread pkg/sip/media_port.go
negotiated *sdp.MediaConfig

audioIn *msdk.WriteCloserSwitch[msdk.PCM16Sample] // SIP RTP -> LK PCM
audioOut *msdk.WriteCloserSwitch[msdk.PCM16Sample] // LK PCM -> SIP RTP

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.

Aren't they safe to use as zero values?

Comment thread pkg/sip/inbound.go Outdated
Comment thread pkg/sip/inbound.go Outdated
if s.cli != nil { // Process reinvite for existing outbound calls
oc := s.cli.getActiveCall(cc.ID())
newCSeq := cc.InviteCSeq()
if oc != nil && oc.cc != nil && oc.cc.InviteCSeq() < newCSeq {

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.

This is pre-existing, behavior, but, in a follow-up PR, we should reply with some kind of error if the new sequence number is lower than the existing one (per spec, I think this should be internal server error). Adding a todo.

Comment thread pkg/sip/inbound.go Outdated
Comment thread pkg/sip/outbound.go Outdated
Comment thread pkg/sip/inbound.go Outdated
Comment thread pkg/sip/outbound.go Outdated

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

3 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment thread pkg/sip/outbound.go
Comment on lines +825 to +827
if old := c.lkRoom.WriteOutboundAudioTo(nil); old != nil {
old.Close()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Dial-tone transfer closes the reused outbound audio writer

When a transfer plays dial-tone, WriteOutboundAudioTo(nil) returns the media port's own outbound writer and old.Close() closes it. That same writer (GetOutboundAudioWriter) is then used to play ringback and is re-attached to the room if the transfer fails, so ringback can be silent and a failed transfer can leave the caller with no room audio.

Suggested change
if old := c.lkRoom.WriteOutboundAudioTo(nil); old != nil {
old.Close()
}
c.lkRoom.WriteOutboundAudioTo(nil)
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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