Beta status: Supported. REFER (RFC 3515) with an RFC 3891
Replacesis beta-supported. SeeCOMPATIBILITY_MATRIX.md.
An attended (consultative) transfer: the transferor talks to the transfer
target before completing the transfer. Alice calls Bob; Bob places a
consultation call to Charlie; then Bob attended-transfers Alice to
Charlie. Unlike a blind transfer, the REFER carries a Replaces header that
identifies the consultation dialog.
Three primitives make this work (all on SessionHandle):
consultation.dialog_identity()→ the SIP dialog identity (Call-ID + tags).DialogIdentity::to_replaces_value()→ formats it as an RFC 3891Replaces.original.transfer_attended(target, &replaces)→ sends Alice a REFER whose Refer-To target embeds thatReplaces.
Alice completes the transfer by calling the Refer-To target; the embedded
Replaces (also surfaced separately on Event::ReferReceived.replaces) ties the
new call to the consultation leg.
- Alice (
:5080) calls Bob (:5081); Bob answers (the original call). - Bob calls Charlie (
:5082) — the consultation call — and waits for answer. - Bob reads the consultation's
dialog_identity, formatsReplaces, and callstransfer_attendedon the Alice leg. - Alice receives the REFER (with
Replaces), hangs up with Bob, and calls the Refer-To target. Charlie answers the transferred call. ✅
Ports default to 5080–5082 so the combined examples-smoke suite does not
collide with quickstart-p2p / SRTP demos that use 5060/5061.
Alice (:5080) ── INVITE ─▶ Bob (:5081) ── INVITE (consult) ─▶ Charlie (:5082)
│ ◀── REFER (Refer-To: Charlie; Replaces=consult dialog) ──┘
│ hangup Bob
└──────────────── INVITE (completes transfer) ─▶ Charlie ✅ connected
./run_demo.shOr manually, in three terminals (defaults shown):
CHARLIE_PORT=5082 cargo run --bin charlie
BOB_PORT=5081 CHARLIE_PORT=5082 cargo run --bin bob
ALICE_PORT=5080 BOB_PORT=5081 cargo run --bin alice [ALICE] Got REFER to sip:charlie@127.0.0.1:5082
[ALICE] Replaces = Some("session-…@rvoip-sip;to-tag=…;from-tag=…")
[ALICE] ✅ Connected to Charlie (attended transfer complete).
[BOB] Consultation with Charlie established.
[BOB] Attended-transferring Alice to Charlie (Replaces=…)
[CHARLIE] Consultation answered.
[CHARLIE] ✅ Answered transferred call.
✅ DEMO SUCCESSFUL — Alice was attended-transferred to Charlie
- The transferor side uses the supported attended-transfer primitives
(
dialog_identity,to_replaces_value,transfer_attended). The transferee side (placing the replacing INVITE) is application orchestration — this example shows the canonical implementation.
- "consultation dialog identity not confirmed yet" — the consultation call wasn't fully answered before Bob read its identity; the example waits, but a slow/declined Charlie can trip this.
- Port conflicts — override the
*_PORTenv vars.
- 05-blind-transfer — the simpler, no-consultation form.
- 10-call-center-b2bua — server-side call handling.
- API reference:
SessionHandle::transfer_attended.