The call setup above assumes parameters NUTAG_AUTOALERT(0), NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
Alice Proxy Bob 0 | | | 1 nua_handle() | | | 2 nua_invite() -> |-----INVITE---->| | 3 nua_i_state <- | | | 4 | |-----INVITE---->| -> nua_i_invite 5 |<--100 Trying---| | -> nua_i_state 6 | | | 7 | | | 8 | | | 9 | |<--180 Ringing--| <- nua_respond(180) 10 nua_i_invite <- |<--180 Ringing--| | -> nua_i_state 11 nua_i_state <- | | | 12 | |<--200 OK-------| <- nua_respond(200) 13 nua_i_invite <- |<---200 OK------| | -> nua_i_state 14 nua_i_state <- | | | 15 nua_ack() -> |-----ACK------->| | 16 nua_i_state <- | |-----ACK------->| -> nua_i_ack 17 | | | -> nua_i_state 18 | | | 19 <<====== SIP Session Established =======>> 20 | | | 21 | | | 22 nua_bye() -> |-----BYE------->| | 23 | |-----BYE------->| -> nua_i_bye 24 | |<----200 OK-----| -> nua_i_state 25 nua_r_bye <- |<---200 OK------| | 26 nua_i_state <- | | | | | |
The call hold is usully implemented using re-INVITE. Re-INVITE is an INVITE request sent on existing SIP session. Both original caller and callee can send re-INVITEs. The main use of re-INVITE is modifying sessions: adding media lines to the session, changing codecs on existing media, and, as you might expect, putting existing media on hold as well as resuming media from hold.
A re-INVITE is sent by calling nua_invite() on handle with existing call. When putting call on hold, the application can include SOATAG_HOLD("audio") or SOATAG_HOLD("video") or SOATAG_HOLD("audio, video") or SOATAG_HOLD("*") as parameters to re-INVITE nua_invite(). (Note that last SOATAG_HOLD() in the tag list will override the SOATAG_HOLD() tags before it.)
Another feature where nua tries to be helpful is autoanswer and auto-ACK on existing sessions: the re-INVITE is automatically responded with 200 OK and ACK is automatically sent. (If the application wants to respond and ACK by itself, it should explicitly set NUTAG_AUTOANSWER(0) and/or NUTAG_AUTOACK(0) in the handle; either include them in nua_invite() or nua_respond() parameters or call nua_set_hparams() explicitly.
Alice Proxy Bob 0 nua_handle() | | | 1 | | | 2 nua_invite() -> |-----INVITE---->| | 3 nua_i_state <- | | | 4 | |-----INVITE---->| -> nua_i_invite 5 |<--100 Trying---| | -> nua_i_state 6 | | | 7 | | | 8 | | | 9 | |<--180 Ringing--| <- nua_respond(180) 10 nua_i_invite <- |<--180 Ringing--| | -> nua_i_state 11 nua_i_state <- | | | 12 | |<--200 OK-------| <- nua_respond(200) 13 nua_i_invite <- |<---200 OK------| | -> nua_i_state 14 nua_i_state <- | | | 15 nua_ack() -> |-----ACK------->| | 16 nua_i_state <- | |-----ACK------->| -> nua_i_ack 17 | | | -> nua_i_state 18 | | | 19 <<== Bi-Directional RTP Established ==>> 20 | | | 21 | | | 22 | |<--INVITE(hold)-| <- nua_invite(.. 21 | | | NUTAG_HOLD("*")..) 23 nua_i_invite <- |<-INVITE(hold)--| | -> nua_i_state 25 nua_i_state <- |----200 OK----->| | 26 | |----200 OK----->| -> nua_i_invite 28 | |<-----ACK-------| -> nua_i_state 29 nua_i_ack <- |<----ACK--------| | 24 | | | 30 <<== Uni-Directional RTP Established ==>> 24 | | | 31 | | | 32 | |<--INVITE-------| <- nua_invite(.. 21 | | | NUTAG_HOLD(NULL)..) 33 nua_i_invite <- |<--INVITE-------| | -> nua_i_state 35 nua_i_state <- |---200 OK------>| | 36 | |---200 OK------>| -> nua_i_invite 38 | |<----ACK--------| -> nua_i_state 39 nua_i_ack <- |<----ACK--------| | 40 nua_i_state <- | | | 19 <<== Bi-Directional RTP Established ==>> 42 | | | 43 nua_bye() -> |-----BYE------->| | 44 nua_i_state <- | |-----BYE------->| -> nua_i_bye 46 | |<----200 OK-----| -> nua_i_state 47 |<---200 OK------| | | | |
1st MSC showing Alice's end:
Alice Bob Carol 0 | | | 1 nua_i_invite <- |<-----INVITE--------| | 2 nua_i_state <- | | | 2 | | | 3 nua_respond(180) -> |----180 Ringing---->| | 2 nua_i_state <- | | | 4 | | | 5 nua_respond(200) -> |------200 OK------->| | 6 nua_i_state <- | | | 8 | | | 7 nua_i_ack <- |<-------ACK---------| | 8 nua_i_state <- | | | 9 |<========RTP=======>| | 10 | | | 11 << Alice performs unattended transfer >> | 12 | | | 13 | | | 14 nua_refer() -> |---REFER("r: C")--->| | 15 | | | 16 nua_r_refer <- |<---202 Accepted----| | 17 | | | 18 nua_i_notify <- |<-----NOTIFY--------| | 19 | | | 20 |------200 OK------->| | 21 | |---INVITE("b: A")-->| 23 | | | 22 nua_bye() -> |-------BYE--------->| | 23 | | | 24 nua_r_bye <- |<----200 OK---------| | 25 nua_i_state <- | No RTP Session | | 28 | |<----180 Ringing----| 26 nua_i_notify <- |<- - -NOTIFY - - - -| | 27 | | | 20 |- - - 200 OK- - - ->| | 29 | | | 30 | |<------200 OK-------| 31 | | | 32 | |---------ACK------->| 33 | | RTP | 34 | |<==================>| 35 | | | 36 |<-----NOTIFY--------| | 37 | | | 38 |------200 OK------->| | | | |
2nd MSC showing Bobs's end:
Alice Bob (nh1) Bob (nh2) Carol 0 | | | | 1 |<-----INVITE--------| | | 2 | | | | 3 |---180 Ringing----->| | | 4 | | | | 5 |------200 OK------->| | | 6 | | | | 7 |<-------ACK---------| | | 8 | RTP | | | 9 |<==================>| | | 10 | | | | 11<< Alice performs unattended transfer >> | | 12 | | | | 13 | Refer-To:C F5| | | 14 |-REFER------------->| -> nua_i_refer | | 15 | | | | 16 |<-202 Accepted------| | | 17 | | | | 18 |<-----NOTIFY--------| | | 19 | | | | 20 |------200 OK------->| -> nua_r_notify | | 21 | | | | 22 |-------BYE--------->| -> nua_i_bye | | 23 | | -> nua_i_state | | 24 |<----200 OK---------| nua_handle() -> | | 25 | No RTP Session | nua_invite() -> | | 26 | | |--INVITE("b: A")--->| 27 | | | | 28 | | nua_i_invite <- |<--180 Ringing------| 29 | | nua_i_state <- | | 30 | | nua_i_invite <- |<----200 OK---------| 31 | | nua_i_state <- | | 32 | | nua_ack -> |-------ACK--------->| 33 | | | | 34 | | |<=======RTP========>| 35 | | | | 36 |<-----NOTIFY--------| | | 37 | | 38 |------200 OK------->| -> nua_r_notify 39 | | <- nua_handle_destroy | |
Bob includes nh1 in nua_invite()/25 as NUTAG_NOTIFY_REFER() parameter.
Open Issue 1:
The call setup below assumes parameters NUTAG_AUTOALERT(0), NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
A B 0 nua_handle() | | 1 nua_invite() -> | | 2 nua_i_state <- |----INVITE (offer)---->| 3 | | -> nua_i_invite 4 | | -> nua_i_state 5 | | 6 | | <- nua_respond(183) 7 nua_i_invite <- |<----183 (answer)------| -> nua_i_state 8 nua_i_state <- | | 9 << single codec is selected now >> 10 |-----PRACK(offer2)---->| -> nua_i_prack 11 | | -> nua_i_state 12 nua_r_prack <- |<--200/PRACK(answer2)--| 13 | | 14 | | 15 << resource reservations are done now >> 16 | | 17 nua_update() -> |----UPDATE (offer3)--->| 18 nua_i_state <- | | 19 nua_i_state <- |<-200/UPDATE (answer3)-| -> nua_i_update 20 | | -> nua_i_state 21 | | 22 | | << B rings >> 23 | | 24 | | <- nua_respond(180) 25 nua_i_invite <- |<---------180----------| 26 nua_i_state <- | | 27 |--------PRACK--------->| -> nua_i_prack 28 nua_r_prack <- |<-----200/PRACK------->| -> nua_i_state 29 | | 30 | | <- nua_respond(200) 31 nua_i_invite <- |<---------200----------| -> nua_i_state 32 nua_i_state <- | | 33 nua_ack() -> | | 34 nua_i_state <- |----------ACK--------->| -> nua_i_ack 35 | | -> nua_i_state | |