.incoming_request = chan_pjsip_incoming_ack,
};
+static int chan_pjsip_incoming_prack(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
+
+static struct ast_sip_session_supplement chan_pjsip_prack_supplement = {
+ .method = "PRACK",
+ .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL,
+ .incoming_request = chan_pjsip_incoming_prack,
+};
+
/*! \brief Function called by RTP engine to get local audio RTP peer */
static enum ast_rtp_glue_result chan_pjsip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
{
{
struct topology_change_refresh_data *refresh_data = data;
struct ast_sip_session *session = refresh_data->session;
+ enum ast_channel_state state = ast_channel_state(session->channel);
+ enum ast_sip_session_refresh_method method = AST_SIP_SESSION_REFRESH_METHOD_INVITE;
int ret;
SCOPE_ENTER(3, "%s: %s\n", ast_sip_session_get_name(session),
ast_str_tmp(256, ast_stream_topology_to_str(refresh_data->media_state->topology, &STR_TMP)));
+ /* See RFC 6337, especially section 3.2: If the early media SDP was sent reliably, we are allowed
+ * to send UPDATEs. Only relevant for AST_STATE_RINGING and AST_STATE_RING - if the channel is UP,
+ * re-INVITES can be sent.
+ */
+ if (session->early_confirmed && (state == AST_STATE_RINGING || state == AST_STATE_RING)) {
+ method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE;
+ }
ret = ast_sip_session_refresh(session, NULL, NULL, on_topology_change_response,
- AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, refresh_data->media_state);
+ method, 1, refresh_data->media_state);
refresh_data->media_state = NULL;
topology_change_refresh_data_free(refresh_data);
pjsip_rdata_sdp_info *sdp = pjsip_rdata_get_sdp_info(rdata);
if (sdp && sdp->body.ptr) {
ast_trace(-1, "%s: Queueing PROGRESS\n", ast_sip_session_get_name(session));
+ session->early_confirmed = pjsip_100rel_is_reliable(rdata) == PJ_TRUE;
ast_queue_control(session->channel, AST_CONTROL_PROGRESS);
} else {
ast_trace(-1, "%s: Queueing RINGING\n", ast_sip_session_get_name(session));
ast_trace(-1, "%s: Queueing PROGRESS\n", ast_sip_session_get_name(session));
ast_trace(1, "%s Method: %.*s Status: %d Queueing PROGRESS with SDP\n", ast_sip_session_get_name(session),
(int)rdata->msg_info.cseq->method.name.slen, rdata->msg_info.cseq->method.name.ptr, status.code);
+ session->early_confirmed = pjsip_100rel_is_reliable(rdata) == PJ_TRUE;
ast_queue_control(session->channel, AST_CONTROL_PROGRESS);
}
} else {
SCOPE_EXIT_RTN_VALUE(0, "%s\n", ast_sip_session_get_name(session));
}
+static int chan_pjsip_incoming_prack(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
+{
+ SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
+
+ if (pj_strcmp2(&rdata->msg_info.msg->line.req.method.name, "PRACK") == 0 &&
+ pjmedia_sdp_neg_get_state(session->inv_session->neg) == PJMEDIA_SDP_NEG_STATE_DONE) {
+
+ session->early_confirmed = 1;
+ }
+ SCOPE_EXIT_RTN_VALUE(0, "%s\n", ast_sip_session_get_name(session));
+}
+
static int update_devstate(void *obj, void *arg, int flags)
{
ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE,
ast_sip_session_register_supplement(&call_pickup_supplement);
ast_sip_session_register_supplement(&pbx_start_supplement);
ast_sip_session_register_supplement(&chan_pjsip_ack_supplement);
+ ast_sip_session_register_supplement(&chan_pjsip_prack_supplement);
if (pjsip_channel_cli_register()) {
ast_log(LOG_ERROR, "Unable to register PJSIP Channel CLI\n");
ao2_cleanup(pjsip_uids_onhold);
pjsip_uids_onhold = NULL;
ast_sip_session_unregister_supplement(&chan_pjsip_ack_supplement);
+ ast_sip_session_unregister_supplement(&chan_pjsip_prack_supplement);
ast_sip_session_unregister_supplement(&pbx_start_supplement);
ast_sip_session_unregister_supplement(&chan_pjsip_supplement_response);
ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
ast_sip_session_unregister_supplement(&pbx_start_supplement);
ast_sip_session_unregister_supplement(&chan_pjsip_ack_supplement);
+ ast_sip_session_unregister_supplement(&chan_pjsip_prack_supplement);
ast_sip_session_unregister_supplement(&call_pickup_supplement);
ast_sip_unregister_service(&refer_callback_module);