]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res/res_pjsip_session: allow SDP answer to be regenerated
authorTorrey Searle <torrey@voxbone.com>
Mon, 21 Aug 2017 09:28:52 +0000 (11:28 +0200)
committerTorrey Searle <tsearle@gmail.com>
Fri, 25 Aug 2017 07:53:13 +0000 (02:53 -0500)
If an SDP answer hasn't been sent yet, it's legal to change it.
This is required for PJSIP_DTMF_MODE to work correctly, and can
also have use in the future for updating codecs too.

ASTERISK-27209 #close

Change-Id: Idbbfb7cb3f72fbd96c94d10d93540f69bd51e7a1

channels/pjsip/dialplan_functions.c
include/asterisk/res_pjsip_session.h
res/res_pjsip_session.c
res/res_pjsip_session.exports.in

index 13d9fab3ad15b3d4b10740e67382c859503b2e77..857684af66daee6796a9c5a55849e31093d8a51f 100644 (file)
@@ -1113,10 +1113,13 @@ static int dtmf_mode_refresh_cb(void *obj)
        struct refresh_data *data = obj;
 
        if (data->session->inv_session->state == PJSIP_INV_STATE_CONFIRMED) {
-               ast_debug(3, "Changing DTMF mode on channel %s after OFFER/ANSER completion. Sending session refresh\n", ast_channel_name(data->session->channel));
+               ast_debug(3, "Changing DTMF mode on channel %s after OFFER/ANSWER completion. Sending session refresh\n", ast_channel_name(data->session->channel));
 
                ast_sip_session_refresh(data->session, NULL, NULL,
                        sip_session_response_cb, data->method, 1);
+       } else if (data->session->inv_session->state == PJSIP_INV_STATE_INCOMING) {
+               ast_debug(3, "Changing DTMF mode on channel %s during OFFER/ANSWER exchange. Updating SDP answer\n", ast_channel_name(data->session->channel));
+               ast_sip_session_regenerate_answer(data->session, NULL);
        }
 
        return 0;
index ca331cbcc422a60d8b2a5fdbabf7d6bc341e155a..d275c256eeeda568972d73795bfae30eca89b3c9 100644 (file)
@@ -625,6 +625,23 @@ int ast_sip_session_refresh(struct ast_sip_session *session,
                enum ast_sip_session_refresh_method method,
                int generate_new_sdp);
 
+/*!
+ * \brief Regenerate SDP Answer
+ *
+ * This method is used when an SDP offer has been received but an SDP answer
+ * has not been sent yet. It requests that a new local SDP be created and
+ * set as the SDP answer. As with any outgoing request in res_pjsip_session,
+ * this will call into registered supplements in case they wish to add anything.
+ *
+ * \param session The session on which the answer will be updated
+ * \param on_sdp_creation Callback called when SDP is created
+ * \param generate_new_sdp Boolean to indicate if a new SDP should be created
+ * \retval 0 Successfully updated the SDP answer
+ * \retval -1 Failure to updated the SDP answer
+ */
+int ast_sip_session_regenerate_answer(struct ast_sip_session *session,
+               ast_sip_session_sdp_creation_cb on_sdp_creation);
+
 /*!
  * \brief Send a SIP response
  *
index 2eb111ce882ceb4ccab1357ebdb76e0b640df33c..42d37fe0c0590ee47fbb433699e802e038b0c46c 100644 (file)
@@ -968,6 +968,46 @@ int ast_sip_session_refresh(struct ast_sip_session *session,
        return 0;
 }
 
+int ast_sip_session_regenerate_answer(struct ast_sip_session *session,
+               ast_sip_session_sdp_creation_cb on_sdp_creation)
+{
+       pjsip_inv_session *inv_session = session->inv_session;
+       pjmedia_sdp_session *new_answer = NULL;
+       const pjmedia_sdp_session *previous_offer = NULL;
+
+       /* The SDP answer can only be regenerated if it is still pending to be sent */
+       if (!inv_session->neg || (pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER &&
+               pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO)) {
+               ast_log(LOG_WARNING, "Requested to regenerate local SDP answer for channel '%s' but negotiation in state '%s'\n",
+                       ast_channel_name(session->channel), pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(inv_session->neg)));
+               return -1;
+       }
+
+       pjmedia_sdp_neg_get_neg_remote(inv_session->neg, &previous_offer);
+       if (pjmedia_sdp_neg_get_state(inv_session->neg) == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {
+               /* Transition the SDP negotiator back to when it received the remote offer */
+               pjmedia_sdp_neg_negotiate(inv_session->pool, inv_session->neg, 0);
+               pjmedia_sdp_neg_set_remote_offer(inv_session->pool, inv_session->neg, previous_offer);
+       }
+
+       new_answer = create_local_sdp(inv_session, session, previous_offer);
+       if (!new_answer) {
+               ast_log(LOG_WARNING, "Could not create a new local SDP answer for channel '%s'\n",
+                       ast_channel_name(session->channel));
+               return -1;
+       }
+
+       if (on_sdp_creation) {
+               if (on_sdp_creation(session, new_answer)) {
+                       return -1;
+               }
+       }
+
+       pjsip_inv_set_sdp_answer(inv_session, new_answer);
+
+       return 0;
+}
+
 void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
 {
        handle_outgoing_response(session, tdata);
index fdfc5fb4724615c568bf91985299bc34519a7ec3..5bc0bf40e26e56cde6383f914fa25da90b7b4576 100644 (file)
@@ -14,6 +14,7 @@
                LINKER_SYMBOL_PREFIXast_sip_session_remove_datastore;
                LINKER_SYMBOL_PREFIXast_sip_session_get_identity;
                LINKER_SYMBOL_PREFIXast_sip_session_refresh;
+               LINKER_SYMBOL_PREFIXast_sip_session_regenerate_answer;
                LINKER_SYMBOL_PREFIXast_sip_session_send_response;
                LINKER_SYMBOL_PREFIXast_sip_session_send_request;
                LINKER_SYMBOL_PREFIXast_sip_session_create_invite;