feat!: Opus SDP negotiation with pinned re-offers#49
Merged
Conversation
Per wavekat-voice doc 45: - build_sdp_offer advertises the full menu Opus-first (opus/48000/2 at PT 111 with useinbandfec=1), G.711 after, telephone-event at both the 8 kHz and 48 kHz clocks - answers are a real RFC 3264 intersection: IncomingCall::accept picks Opus wherever offered (at the offer's PT) else the first G.711, echoes only that selection, and answers 488 when nothing matches - every post-negotiation re-offer (hold/resume, and consumer-built refresh bodies) pins the negotiated codec via CodecMenu::Pinned so a re-INVITE can't renegotiate the codec under a live audio path - parse_sdp resolves dynamic payload types into RemoteMedia::codec / opus_payload_type and records telephone-event entries at any clock (DtmfSpec); RemoteMedia::dtmf picks the clock-matched entry - DtmfBurstConfig gains clock_rate: duration ticks and pacing follow the negotiated event clock (160/20 ms at 8 kHz, 960 at 48 kHz) BREAKING CHANGE: build_sdp/build_sdp_with are replaced by build_sdp_offer and a CodecMenu-taking build_sdp_with; RemoteMedia::dtmf_payload_type is replaced by dtmf_events/dtmf() and RemoteMedia gains codec/opus_payload_type; DtmfBurstConfig gains a required clock_rate field. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
wavekat-eason
marked this pull request as ready for review
July 3, 2026 07:32
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Teaches
wavekat-sip's SDP layer to negotiate Opus wideband alongside G.711, with real RFC 3264 answer intersection and codec-pinned re-offers so a mid-call re-INVITE can't renegotiate under a live audio path. This is thewavekat-siphalf of the WaveKat Voice Opus work (voice doc 45); it pairs withwavekat-core0.0.13 (theopusfeature) and lands second in the publish order.The crate stays codec-agnostic — it advertises and resolves payload types and clocks; the actual encode/decode lives in
wavekat-core. No new dependency.What changes
build_sdp_offeradvertises the full menu Opus-first (opus/48000/2at PT 111 withuseinbandfec=1), G.711 after, andtelephone-eventat both the 8 kHz and 48 kHz clocks.IncomingCall::acceptpicks Opus wherever the offer carries it (at the offer's PT), else the first G.711, echoes only that one selection, and answers 488 when nothing matches.CodecMenu::Pinned, so a re-INVITE can't swap the codec while audio is flowing.parse_sdpresolves dynamic payload types intoRemoteMedia::codec/opus_payload_typeand recordstelephone-evententries at any clock (DtmfSpec);RemoteMedia::dtmfreturns the clock-matched entry.DtmfBurstConfig.clock_rate— burst duration ticks and pacing follow the negotiated event clock (160/20 ms at 8 kHz, 960 at 48 kHz).BREAKING CHANGE → releases as 0.2.0
build_sdp/build_sdp_withare replaced bybuild_sdp_offerand aCodecMenu-takingbuild_sdp_with.RemoteMedia::dtmf_payload_typeis replaced bydtmf_events/dtmf();RemoteMediagainscodec/opus_payload_type.DtmfBurstConfiggains a requiredclock_ratefield.Test plan
cargo test -p wavekat-sip— 229 lib tests + integration + doctests pass.cargo fmt --all -- --checkclean.tests/end_to_end_call.rs) negotiates Opus over real UDP sockets; a raw G.711-only INVITE exercises the legacy intersection path (and the 488-on-no-match path is covered).docs/RFC-COVERAGE.mdupdated for the new negotiation/answer behavior.Notes for review
wavekat-core0.0.13 is already published; this publishes next as 0.2.0 (breaking), then WaveKat Voice drops its local[patch.crates-io]and pins the released versions.🤖 Generated with Claude Code