= Background = == pjsua_call.c == Currently this is how the media channel interacts with SIP call in PJSUA-LIB. '''pjsua_call_make_call()''' : :: '''pjsua_call_on_incoming()''' : :: '''pjsua_call_update()''' : :: '''pjsua_call_reinvite()''' : :: '''pjsua_call_on_rx_offer()''' : :: '''pjsua_call_on_create_offer()''' : :: pjsua_media_channel_init();[[BR]] pjsua_media_channel_create_sdp(&local_sdp, rem_sdp); '''pjsua_call_on_media_update()''' : :: pjsua_media_channel_update(); '''pjsua_call_on_state_changed(DISCONNECTED)''' : :: '''pjsua_call_on_media_update(HOLD)''' : :: pjsua_media_channel_deinit(); == pjsua_media.c == and this is the implementation of media channel functions above: '''pjsua_media_channel_init()''' : :: pjmedia_transport_srtp_create(); '''pjsua_media_channel_create_sdp()''' : :: pjmedia_endpt_create_sdp();[[BR]] pjmedia_transport_media_create(); '''pjsua_media_channel_update()''' : :: pjmedia_transport_media_start();[[BR]] pjmedia_session_create(); '''pjsua_media_channel_deinit()''' : :: stop_media_session();[[BR]] pjmedia_transport_media_stop();[[BR]] pjmedia_transport_close(srtp); = New = ''New code in italics''. == pjsua_call.c == Currently this is how the media channel interacts with SIP call in PJSUA-LIB. '''pjsua_call_make_call()''' : :: '''pjsua_call_on_incoming()''' : :: ~~pjsua_media_channel_init();~~[[BR]] ~~pjsua_media_channel_create_sdp(&local_sdp, rem_sdp);~~[[BR]] ''pjsua_media_channel_init(&local_sdp, rem_sdp);'' '''pjsua_call_update()''' : :: '''pjsua_call_reinvite()''' : :: '''pjsua_call_on_rx_offer()''' : :: '''pjsua_call_on_create_offer()''' : :: ~~pjsua_media_channel_init(&local_sdp, rem_sdp);~~[[BR]] pjsua_media_channel_create_sdp(&local_sdp, rem_sdp); '''pjsua_call_on_media_update()''' : :: pjsua_media_channel_update(); '''pjsua_call_on_state_changed(DISCONNECTED)''' : :: '''pjsua_call_on_media_update(HOLD)''' : :: pjsua_media_channel_deinit(); == pjsua_media.c == and this is the implementation of media channel functions above: '''pjsua_media_channel_init(&local_sdp, rem_sdp)''' : :: pjmedia_transport_srtp_create();[[BR]] ~~pjmedia_transport_media_create(local_sdp, rem_sdp);~~[[BR]] ''pjmedia_transport_media_create(rem_sdp);''[[BR]] ''pjmedia_transport_encode_sdp(local_sdp, rem_sdp);'' '''pjsua_media_channel_create_sdp(&local_sdp, rem_sdp)''' : :: pjmedia_endpt_create_sdp();[[BR]] ~~pjmedia_transport_media_create(local_sdp, rem_sdp);~~[[BR]] ''pjmedia_transport_encode_sdp(local_sdp, rem_sdp);'' '''pjsua_media_channel_update()''' : :: pjmedia_transport_media_start();[[BR]] pjmedia_session_create(); '''pjsua_media_channel_deinit()''' : :: stop_media_session();[[BR]] pjmedia_transport_media_stop();[[BR]] pjmedia_transport_close(srtp); == Changes in Transport == {{{media_create()}}}:: 1. The semantic has changed: - previously this function is always called everytime we want to send offer - now this function is only called once when the transport needs to be created. Meaning once before call, and once the session is woken up after call hold. When media is already created and the application wants to send offer, it will just call {{{encode_sdp()}}} below without re-creating the media. 1. The syntax has changed: - ''local_sdp'' parameter is removed. Local SDP should be populated in {{{encode_sdp()}}} instead. This is to make it consistent since SDP can be created without re-creating media. '''New:''' {{{encode_sdp()}}}:: 1. This function is used to modify local SDP with transport info. It can be called for different purposes below. 1. '''generating initial offer''': this happens for outgoing calls, right after {{{media_create()}}} is called. The transport must initialize local SDP with default values (for ICE: include all candidates. For SRTP: include all crypto options). Normally it does not need to modify it's state. 1. '''generating initial answer''': this happens for incoming calls, also right after {{{media_create()}}} is called. The transport must inspect the remote SDP '''and'''' update the transport according to the info in remote SDP '''and''' update local SDP to be sent as answer. For example: disable the feature if remote SDP doesn't contain the required attributes. 1. '''generating subsequent offer''': this happens when local endpoint sends UPDATE or re-INVITE. In this case, the transport '''MUST NOT''' modify it's state, and rather just encode it's current state in the local SDP. 1. '''generating subsequent answer''': this happens when we receive UPDATE or re-INVITE. The processing is similar to ''generating initial answer'' above. {{{media_start()}}}:: 1. The syntax has changed: - the local SDP is now ''const''. This is because it's useless to modify the local SDP there since the SDP has already been negotiated. == Bug == With the new framework, there's still a bug. The offer/answer RFC says that if UPDATE or re-INVITE fails, the media should remain unchanged, i.e. it falls back to use the previously successfully negotiated media. That's not possible with the framework above, for the '''generating subsequent answer''' case above. Solving this is currently not possible with ICE, since that requires creating a new/fresh ''ice_strans'' everytime we receive updated offer, just in case the offer/answer fails so that we can revert back to old ''ice_strans''.