Skip to content

Navigation Menu

Sign in
Sign up

fix: cache participant attrs for BYE attributes_to_headers (#404) - #775

Open
lixuanqun wants to merge 1 commit into
livekit:main from
lixuanqun:cursor/fix-bye-attrs-headers-33f3
Open

fix: cache participant attrs for BYE attributes_to_headers (#404) #775
lixuanqun wants to merge 1 commit into
livekit:main from
lixuanqun:cursor/fix-bye-attrs-headers-33f3

Conversation

@lixuanqun

@lixuanqun lixuanqun commented Aug 4, 2026

Copy link
Copy Markdown

When an agent hangs up by deleting the room, LocalParticipant is gone before SIP sends BYE, so attributes_to_headers mapping was skipped and custom X-* headers were missing.

Cache the last-seen participant attributes on join/update and reuse them when building BYE/REFER headers if the room is already nil. Applies to inbound and outbound calls.

Fixes #404

When an agent hangs up by deleting the room, LocalParticipant is gone
before SIP sends BYE, so attributes_to_headers mapping was skipped and
custom X-* headers were missing.
Cache the last-seen participant attributes on join/update and reuse them
when building BYE/REFER headers if the room is already nil. Applies to
inbound and outbound calls.
Fixes livekit#404
Co-authored-by: li xuanqun <793005378@qq.com>
lixuanqun requested a review from a team as a code owner August 4, 2026 03:32

@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 potential issue.

View 1 additional finding in Devin Review.

Open in Devin Review

Comment thread pkg/sip/inbound.go
Comment on lines +1817 to +1820
attrs := r.LocalParticipant.Attributes() // clones
c.attrsMu.Lock()
c.cachedAttrs = attrs
c.attrsMu.Unlock()

@devin-ai-integration devin-ai-integration Bot Aug 4, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Saved caller attributes can be wiped out by an empty refresh, so custom hangup headers are lost again

The stored copy of the caller's attributes is unconditionally replaced with whatever the live room reports (c.cachedAttrs = attrs at pkg/sip/inbound.go:1817-1820), even when that live report is empty, so the values kept for the hangup message can be erased and the custom headers go missing again.
Impact: In the exact teardown situation this change is meant to fix, the outgoing hangup can still be sent without the configured custom headers.

How an empty live read overwrites the seeded cache

snapshotParticipantAttrs (inbound pkg/sip/inbound.go:1809-1821, outbound pkg/sip/outbound.go:183-195) writes c.cachedAttrs = attrs with no length check, unlike storeParticipantAttrs which deliberately ignores empty input (pkg/sip/inbound.go:1824). Right after seeding the cache from the join config (pkg/sip/inbound.go:1556-1557 and pkg/sip/outbound.go:508-509) a snapshot is taken immediately; if LocalParticipant.Attributes() has not yet been populated it returns an empty map and the seed is discarded. The same holds for participantAttributes() (pkg/sip/inbound.go:1832-1836), which snapshots first: if the room object still exists during teardown but the local participant's attribute map has already been cleared, the good cache is replaced with an empty one and fillHeaders then returns the headers untouched (pkg/sip/inbound.go:1799-1801).

Guarding the write with if len(attrs) == 0 { return } makes the snapshot strictly additive/refreshing and keeps the fallback usable.

Suggested change
attrs := r.LocalParticipant.Attributes() // clones
c.attrsMu.Lock()
c.cachedAttrs = attrs
c.attrsMu.Unlock()
attrs := r.LocalParticipant.Attributes() // clones
if len(attrs) == 0 {
return // do not drop a previously cached snapshot
}
c.attrsMu.Lock()
c.cachedAttrs = attrs
c.attrsMu.Unlock()
Open in Devin Review

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

codecov Bot commented Aug 4, 2026
edited
Loading

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.71930% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.28%. Comparing base (0460b40) to head (cc4b49c).
⚠️ Report is 370 commits behind head on main.

Files with missing lines Patch % Lines
pkg/sip/outbound.go 82.75% 2 Missing and 3 partials ⚠️
pkg/sip/inbound.go 92.85% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@
## main #775 +/- ##
==========================================
+ Coverage 65.25% 66.28% +1.03% 
==========================================
 Files 51 41 -10 
 Lines 6588 7997 +1409 
==========================================
+ Hits 4299 5301 +1002 
- Misses 1915 2206 +291 
- Partials 374 490 +116 

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

Thanks for the fix @lixuanqun. I think it'd be a good idea to implement devin's suggestion for both inbound and outbound calls

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@devin-ai-integration devin-ai-integration[bot] devin-ai-integration[bot] left review comments

At least 1 approving review is required to merge this pull request.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

LiveKit attributes are not mapped to SIP X-* headers when sending BYE

AltStyle によって変換されたページ (->オリジナル) /