Migrating to 1.13.0¶
1.13.0 changes nothing in the Python scripting API's signatures and no
siphon.yaml key stops working. It does break the Rust library API in a few
places, and it changes what siphon puts on the wire in several, all toward what
RFC 3261 says. This page lists both: what an embedder has to change, and what an
operator should check against a running deployment.
The full list is in the 1.13.0 changelog entry.
Rust library¶
Only relevant when you link siphon-sip as a crate.
| What | Change |
|---|---|
transaction::state::Action |
New variant SendCancel. An exhaustive match needs an arm: send cancel.frame to cancel.hop, the way the SendFrame arm sends a retransmission. |
proxy::fork::ForkAction |
New variant ForwardAnother2xx: a 2xx from a second branch, to be forwarded upstream (RFC 3261 §16.7 step 5). |
transaction::timer::TimerName |
New variant C. IctEvent gains TimerC, TimerConfig gains timer_c_secs. |
ReferSubscription::target_leg_call_id |
Replaced by targets, one record per INVITE keyed by Via branch. |
b2bua_complete_terminated_transfer, b2bua_fail_terminated_transfer |
Take the Via branch of the target's INVITE instead of a leg index. The first also takes the source the 2xx came from. |
DelayedOfferAck::b_leg_index |
Replaced by branch. b2bua_fail_after_answer takes a branch. |
An embedder that creates INVITE client transactions itself should record where
each INVITE went (BranchHop), so the CANCEL and the ACK of a failed branch
leave the same way.
Rust control SDK¶
siphon-control-proto and siphon-control-client 0.8.0:
PlayOptions::repeatisOption<PlayRepeat>. A count converts with.into().PlaySourcehas two more variants (Tone,Url), andPlayOptionsandTransferDialhave more public fields. An exhaustivematch, or a struct literal without..Default::default(), needs the addition.
The Python and TypeScript SDKs only gain arguments.
Behaviour to check on a running deployment¶
CANCEL¶
siphon no longer sends a CANCEL for an INVITE that has drawn no response (RFC
3261 §9.1). It keeps retransmitting the INVITE and sends the CANCEL on the first
provisional, on the proxy and on the B2BUA. A far end that never sends 100
Trying and relied on an immediate CANCEL now sees the INVITE retransmitted
until Timer B.
A proxy CANCEL carries the branch's own Request-URI and Route set, not the
caller's, and only Reason is relayed from the caller's CANCEL.
A second 2xx reaches the caller¶
The proxy forwards every 2xx to an INVITE, also one that arrives after another
branch answered, after the caller cancelled or after a script rejected (RFC 3261
§16.7 step 5). The caller's user agent is what ACKs and BYEs the extra dialog.
@proxy.on_reply does not run for such a 2xx and it is not an answer for CDR or
Rf.
Ringing on a proxied call¶
transaction.invite_timeout_secs no longer ages a session that still has a
branch ringing. A proxied call that rang past it (32 s by default) used to lose
its session without a word to either side. Ringing is now bounded by Timer C,
transaction.timer_c_secs, 181 s by default. When it fires the branch is
cancelled and @proxy.on_failure runs.
@proxy.on_failure now also runs for a 487 the caller did not ask for. A
handler that treated every 487 as "the caller hung up" should use
@proxy.on_cancel for that.
CDRs¶
A proxied call the caller cancels, or a script rejects, now gets its CDR: one
487 record per cancelled call and one record per rejected call. A collector
that counted records as answered calls needs to look at response_code.
Media source hints (received_from)¶
Whether a party's media ingress is pinned to its signalling source is now read from that party's own half of the profile, on every command. Profiles that carry the same policy on both halves are unaffected. For the others:
- A callee's re-INVITE or UPDATE is pinned by the
answerhalf, the caller's by theofferhalf, whoever re-offers. rtpengine.answer(reply)stamps the address the reply came from. Withcall=it used to stamp the caller's address on the callee's SDP, and without it nothing. A callee that sends media from another host than it signals from, under a profile withreceived_fromon theanswerhalf, is now gated.
A re-offer is also shaped for the party it is sent to. With a direction-bound
profile (srtp_to_rtp, rtp_to_srtp) a hold from the callee used to reach the
caller in the callee's transport.
Control plane¶
- The reply to
cancel_dialarrives afterDialFailed, once the dial has let go of the caller. - A REFER that arrives while a transfer is in flight on its call is answered
491. A retransmitted REFER gets the response it already got. playanswersbad_requestfor an argument of the wrong type, where it used to play once and answerok.holdon a call the engine only relays answersinvalid_state.routeis refused while adialstill rings.accept_referwithtimeoutin a mode other thancontrollerisbad_request.- A leg parted by
unbridgethat sends a changed offer is answered488. Bridge it again first.