pjsip: reinvite for connected line updates occurs when it should not
[asterisk/asterisk.git] / channels / chan_pjsip.c
index 527ba27..96500b4 100644 (file)
@@ -577,7 +577,7 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s
                return NULL;
        }
 
-       /* If res_sip_session is ever updated to create/destroy ast_sip_session_media
+       /* If res_pjsip_session is ever updated to create/destroy ast_sip_session_media
         * during a call such as if multiple same-type stream support is introduced,
         * these will need to be recaptured as well */
        pvt->media[SIP_MEDIA_AUDIO] = ao2_find(session->media, "audio", OBJ_KEY);
@@ -637,11 +637,17 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s
 
 static int answer(void *data)
 {
-       pj_status_t status;
+       pj_status_t status = PJ_SUCCESS;
        pjsip_tx_data *packet;
        struct ast_sip_session *session = data;
 
-       if ((status = pjsip_inv_answer(session->inv_session, 200, NULL, NULL, &packet)) == PJ_SUCCESS) {
+       pjsip_dlg_inc_lock(session->inv_session->dlg);
+       if (session->inv_session->invite_tsx) {
+               status = pjsip_inv_answer(session->inv_session, 200, NULL, NULL, &packet);
+       }
+       pjsip_dlg_dec_lock(session->inv_session->dlg);
+
+       if (status == PJ_SUCCESS && packet) {
                ast_sip_session_send_response(session, packet);
        }
 
@@ -877,7 +883,7 @@ static int chan_pjsip_devicestate(const char *data)
        RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", data), ao2_cleanup);
        enum ast_device_state state = AST_DEVICE_UNKNOWN;
        RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, NULL, ao2_cleanup);
-       RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, ao2_cleanup);
+       RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
        struct ast_devstate_aggregate aggregate;
        int num, inuse = 0;
 
@@ -894,19 +900,22 @@ static int chan_pjsip_devicestate(const char *data)
                state = AST_DEVICE_NOT_INUSE;
        }
 
-       if (!endpoint_snapshot->num_channels || !(caching_topic = ast_channel_topic_all_cached())) {
+       if (!endpoint_snapshot->num_channels || !(cache = ast_channel_cache())) {
                return state;
        }
 
        ast_devstate_aggregate_init(&aggregate);
 
-       ao2_ref(caching_topic, +1);
+       ao2_ref(cache, +1);
 
        for (num = 0; num < endpoint_snapshot->num_channels; num++) {
-               RAII_VAR(struct stasis_message *, msg, stasis_cache_get_extended(caching_topic, ast_channel_snapshot_type(),
-                       endpoint_snapshot->channel_ids[num], 1), ao2_cleanup);
+               RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
                struct ast_channel_snapshot *snapshot;
 
+               stasis_topic_wait(ast_channel_topic_all_cached());
+               msg = stasis_cache_get(cache, ast_channel_snapshot_type(),
+                       endpoint_snapshot->channel_ids[num]);
+
                if (!msg) {
                        continue;
                }
@@ -1068,6 +1077,7 @@ static int transmit_info_with_vidupdate(void *data)
 static int update_connected_line_information(void *data)
 {
        RAII_VAR(struct ast_sip_session *, session, data, ao2_cleanup);
+       struct ast_party_id connected_id;
 
        if ((ast_channel_state(session->channel) != AST_STATE_UP) && (session->inv_session->role == PJSIP_UAS_ROLE)) {
                int response_code = 0;
@@ -1092,7 +1102,13 @@ static int update_connected_line_information(void *data)
                        method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE;
                }
 
-               ast_sip_session_refresh(session, NULL, NULL, NULL, method, 0);
+               connected_id = ast_channel_connected_effective_id(session->channel);
+               if ((session->endpoint->id.send_pai || session->endpoint->id.send_rpid) &&
+                   (session->endpoint->id.trust_outbound ||
+                    ((connected_id.name.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED &&
+                     (connected_id.number.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED))) {
+                       ast_sip_session_refresh(session, NULL, NULL, NULL, method, 1);
+               }
        }
 
        return 0;
@@ -1159,10 +1175,25 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi
        case AST_CONTROL_VIDUPDATE:
                media = pvt->media[SIP_MEDIA_VIDEO];
                if (media && media->rtp) {
-                       ao2_ref(channel->session, +1);
+                       /* FIXME: Only use this for VP8. Additional work would have to be done to
+                        * fully support other video codecs */
+                       struct ast_format_cap *fcap = ast_channel_nativeformats(ast);
+                       struct ast_format vp8;
+                       ast_format_set(&vp8, AST_FORMAT_VP8, 0);
+                       if (ast_format_cap_iscompatible(fcap, &vp8)) {
+                               /* FIXME Fake RTP write, this will be sent as an RTCP packet. Ideally the
+                                * RTP engine would provide a way to externally write/schedule RTCP
+                                * packets */
+                               struct ast_frame fr;
+                               fr.frametype = AST_FRAME_CONTROL;
+                               fr.subclass.integer = AST_CONTROL_VIDUPDATE;
+                               res = ast_rtp_instance_write(media->rtp, &fr);
+                       } else {
+                               ao2_ref(channel->session, +1);
 
-                       if (ast_sip_push_task(channel->session->serializer, transmit_info_with_vidupdate, channel->session)) {
-                               ao2_cleanup(channel->session);
+                               if (ast_sip_push_task(channel->session->serializer, transmit_info_with_vidupdate, channel->session)) {
+                                       ao2_cleanup(channel->session);
+                               }
                        }
                } else {
                        res = -1;