</condition>
</extension>
+ <extension name="acknowledge_call">
+ <condition field="destination_number" expression="^(.*)$">
+ <action application="acknowledge_call"/>
+ <action application="ring_ready"/>
+ <action application="playback" data="$${hold_music}"/>
+ </condition>
+ </extension>
+
</context>
</include>
-->
<!--<param name="renegotiate-codec-on-hold" value="true"/>-->
+ <!-- By default mod_sofia will send "100 Trying" in response to a SIP INVITE. Set this to false if
+ you want to turn off this behavior and manually send the "100 Trying" via the acknowledge_call application.
+ -->
+ <!--<param name="auto-invite-100" value="false"/>-->
</settings>
</profile>
clone = 1, sip->sip_call_id = sip_call_id_copy(home, irq->irq_call_id);
if (!sip->sip_cseq)
clone = 1, sip->sip_cseq = sip_cseq_copy(home, irq->irq_cseq);
- if (!sip->sip_via)
- clone = 1, sip->sip_via = sip_via_copy(home, irq->irq_via);
+ if (!sip->sip_via) {
+ clone = 1;
+ /* 100 responses are not forwarded by proxies, so only include the topmost Via header */
+ if (sip->sip_status && sip->sip_status->st_status == 100)
+ sip->sip_via = (sip_via_t *)msg_header_copy_one(home, (msg_header_t const *)irq->irq_via);
+ else
+ sip->sip_via = sip_via_copy(home, irq->irq_via);
+ }
if (clone)
msg_set_parent(msg, (msg_t *)irq->irq_home);
if (sip_to_tag(home, sip->sip_to, irq->irq_tag) < 0)
return -1;
- if (status < 300 && !sip->sip_record_route && irq->irq_record_route)
+ if (status > 100 && status < 300 && !sip->sip_record_route && irq->irq_record_route)
if (sip_add_dup(msg, sip, (sip_header_t *)irq->irq_record_route) < 0)
return -1;
NHP_SET(nhp, keepalive, 120000);
+ NHP_SET(nhp, auto_invite_100, 1);
+
NHP_SET(nhp, appl_method,
sip_allow_make(home, "INVITE, REGISTER, PUBLISH, SUBSCRIBE"));
else if (tag == ntatag_default_proxy) {
NHP_SET_STR_BY_URL(nhp, url_string_t, proxy, value);
}
+ /* NUTAG_AUTO_INVITE_100() */
+ else if (tag == nutag_auto_invite_100) {
+ NHP_SET(nhp, auto_invite_100, value != 0);
+ }
/* NUTAG_DETECT_NETWORK_UPDATES(detect_network_updates) */
else if (ngp && tag == nutag_detect_network_updates) {
int detector = (int)value;
/** Enable Retry-After */
unsigned nhp_retry_after_enable:1;
+ /** Enable/Disable automatic 100 Trying when receiving INVITE */
+ unsigned nhp_auto_invite_100:1;
+
unsigned:0;
/* Default lifetime for implicit subscriptions created by REFER */
unsigned nhb_proxy:1;
unsigned nhb_timer_autorequire:1;
unsigned nhb_retry_after_enable:1;
+ unsigned nhb_auto_invite_100:1;
unsigned :0;
} set_bits;
unsigned set_unsigned[2];
if (sr->sr_status <= 100) {
SR_STATUS1(sr, SIP_100_TRYING);
- if (method == sip_method_invite || sip->sip_timestamp) {
+ if ((method == sip_method_invite && nh->nh_prefs->nhp_auto_invite_100) ||
+ sip->sip_timestamp) {
nta_incoming_treply(irq, SIP_100_TRYING,
SIPTAG_USER_AGENT_STR(user_agent),
TAG_END());
nua_server_params(sr, tags);
nua_server_respond(sr, tags);
- nua_server_report(sr);
+
+ if (!(sr->sr_method == sip_method_invite && status == 100)) {
+ /* Since we don't change state, do not notify application when
+ we send 100 Trying for INVITE */
+ nua_server_report(sr);
+ }
}
int nua_server_params(nua_server_request_t *sr, tagi_t const *tags)
goto internal_error;
}
+ if (sr->sr_status == 100) {
+ return nta_incoming_treply(sr->sr_irq, SIP_100_TRYING,
+ SIPTAG_USER_AGENT_STR(NH_PGET(nh, user_agent)),
+ TAG_END());
+ return 0;
+ }
+
if (sr->sr_status < 200) {
next.msg = nta_incoming_create_response(sr->sr_irq, 0, NULL);
next.sip = sip_object(next.msg);
* Reference tag for NUTAG_AUTH_CACHE().
*/
+/**@def NUTAG_AUTO_INVITE_100(x)
+ */
+tag_typedef_t nutag_auto_invite_100 = INTTAG_TYPEDEF(auto_invite_100);
+
+/**@def NUTAG_AUTO_INVITE_100(x)
+ * Reference tag for NUTAG_AUTO_INVITE_100().
+ */
/**@def NUTAG_DETECT_NETWORK_UPDATES(x)
*
nutag_shutdown_events_ref, tag_bool_vr(&(x))
SOFIAPUBVAR tag_typedef_t nutag_shutdown_events_ref;
+#define NUTAG_AUTO_INVITE_100(x) \
+ nutag_auto_invite_100, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_auto_invite_100;
+#define NUTAG_AUTO_INVITE_100_REF(x) \
+ nutag_auto_invite_100_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_auto_invite_100_ref;
+
/* Pass nua handle as tagged argument */
#if SU_INLINE_TAG_CAST
su_inline tag_value_t nutag_handle_v(nua_handle_t *v) { return (tag_value_t)v; }
*/
#define switch_channel_mark_pre_answered(channel) switch_channel_perform_mark_pre_answered(channel, __FILE__, __SWITCH_FUNC__, __LINE__)
+SWITCH_DECLARE(switch_status_t) switch_channel_perform_acknowledge_call(switch_channel_t *channel,
+ const char *file, const char *func, int line);
+#define switch_channel_acknowledge_call(channel) switch_channel_perform_acknowledge_call(channel, __FILE__, __SWITCH_FUNC__, __LINE__)
+
SWITCH_DECLARE(switch_status_t) switch_channel_perform_ring_ready_value(switch_channel_t *channel,
switch_ring_ready_t rv,
const char *file, const char *func, int line);
SWITCH_MESSAGE_REDIRECT_AUDIO,
SWITCH_MESSAGE_TRANSMIT_TEXT,
SWITCH_MESSAGE_INDICATE_ANSWER,
+ SWITCH_MESSAGE_INDICATE_ACKNOWLEDGE_CALL,
SWITCH_MESSAGE_INDICATE_PROGRESS,
SWITCH_MESSAGE_INDICATE_BRIDGE,
SWITCH_MESSAGE_INDICATE_UNBRIDGE,
switch_ivr_capture_text(session, switch_true((char *)data));
}
+SWITCH_STANDARD_APP(acknowledge_call_function)
+{
+ switch_channel_acknowledge_call(switch_core_session_get_channel(session));
+}
+
SWITCH_STANDARD_APP(ring_ready_function)
{
if (!zstr(data)) {
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
SWITCH_ADD_APP(app_interface, "capture_text", "capture text", "capture text", capture_text_function, "", SAF_NONE);
+ SWITCH_ADD_APP(app_interface, "acknowledge_call", "Indicate Call Acknowledged", "Indicate Call Acknowledged on a channel.", acknowledge_call_function, "", SAF_SUPPORT_NOMEDIA);
SWITCH_ADD_APP(app_interface, "ring_ready", "Indicate Ring_Ready", "Indicate Ring_Ready on a channel.", ring_ready_function, "", SAF_SUPPORT_NOMEDIA);
SWITCH_ADD_APP(app_interface, "remove_bugs", "Remove media bugs", "Remove all media bugs from a channel.", remove_bugs_function, "[<function>]", SAF_NONE);
SWITCH_ADD_APP(app_interface, "break", "Break", "Set the break flag.", break_function, "", SAF_SUPPORT_NOMEDIA);
static switch_status_t sofia_on_exchange_media(switch_core_session_t *session);
static switch_status_t sofia_on_soft_execute(switch_core_session_t *session);
+static switch_status_t sofia_acknowledge_call(switch_core_session_t *session);
static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session,
switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause);
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_assert(tech_pvt != NULL);
+ if (sofia_test_pflag(tech_pvt->profile, PFLAG_AUTO_INVITE_100) &&
+ !switch_channel_test_flag(channel, CF_ANSWERED) &&
+ switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
+ if (sofia_acknowledge_call(session) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Call appears to be already acknowledged\n");
+ }
+ }
+
if (!sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
switch_channel_clear_flag(channel, CF_LEG_HOLDING);
return SWITCH_STATUS_SUCCESS;
}
+static switch_status_t sofia_acknowledge_call(switch_core_session_t *session)
+{
+ struct private_object *tech_pvt = switch_core_session_get_private(session);
+
+ if (!tech_pvt->sent_100) {
+ nua_respond(tech_pvt->nh, SIP_100_TRYING, TAG_END());
+ tech_pvt->sent_100 = 1;
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ return SWITCH_STATUS_FALSE;
+}
+
static switch_status_t sofia_answer_channel(switch_core_session_t *session)
{
private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
char *sticky = NULL;
const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full");
+ if(sofia_acknowledge_call(session) == SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Dialplan did not acknowledge_call; sent 100 Trying");
+ }
+
if (switch_channel_test_flag(channel, CF_CONFERENCE) && !switch_stristr(";isfocus", tech_pvt->reply_contact)) {
tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s;isfocus", tech_pvt->reply_contact);
}
}
}
+ /* Dialplan should really use acknowledge_call application instead of respond application to send 100 */
+ if (code == 100) {
+ status = sofia_acknowledge_call(session);
+ goto end_lock;
+ }
+
if (tech_pvt->proxy_refer_uuid) {
if (tech_pvt->proxy_refer_msg) {
nua_respond(tech_pvt->nh, code, su_strdup(nua_handle_home(tech_pvt->nh), reason), SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END());
}
break;
+ case SWITCH_MESSAGE_INDICATE_ACKNOWLEDGE_CALL:
+ status = sofia_acknowledge_call(session);
+ break;
case SWITCH_MESSAGE_INDICATE_RINGING:
{
switch_ring_ready_t ring_ready_val = msg->numeric_arg;
+ if(sofia_acknowledge_call(session) == SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Dialplan did not acknowledge_call; sent 100 Trying");
+ }
+
if (!switch_channel_test_flag(channel, CF_RING_READY) && !sofia_test_flag(tech_pvt, TFLAG_BYE) &&
!switch_channel_test_flag(channel, CF_EARLY_MEDIA) && !switch_channel_test_flag(channel, CF_ANSWERED)) {
char *extra_header = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX);
int send_sip_code = 183;
const char * p_send_sip_msg = sip_183_Session_progress;
+ if(sofia_acknowledge_call(session) == SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Dialplan did not acknowledge_call; sent 100 Trying");
+ }
+
b_sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE);
is_proxy = (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA));
is_3pcc_proxy = (sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY) && sofia_test_flag(tech_pvt, TFLAG_3PCC));
PFLAG_PROXY_INFO,
PFLAG_PROXY_MESSAGE,
PFLAG_FIRE_BYE_RESPONSE_EVENTS,
+ PFLAG_AUTO_INVITE_100,
/* No new flags below this line */
PFLAG_MAX
sip_contact_t *contact;
int q850_cause;
int got_bye;
+ int sent_100;
nua_event_t want_event;
switch_rtp_bug_flag_t rtp_bugs;
char *user_via;
NTATAG_TCP_RPORT(0),
NTATAG_TLS_RPORT(0),
NUTAG_RETRY_AFTER_ENABLE(0),
+ NUTAG_AUTO_INVITE_100(0),
TAG_IF(!strchr(profile->sipip, ':'),
SOATAG_AF(SOA_AF_IP4_ONLY)),
TAG_IF(strchr(profile->sipip, ':'),
}
profile->tls_verify_policy = TPTLS_VERIFY_NONE;
+ sofia_set_pflag(profile, PFLAG_AUTO_INVITE_100);
/* lib default */
profile->tls_verify_depth = 2;
} else {
sofia_clear_pflag(profile, PFLAG_SECURE);
}
+ } else if (!strcasecmp(var, "auto-invite-100")) {
+ if (switch_true(val)) {
+ sofia_set_pflag(profile, PFLAG_AUTO_INVITE_100);
+ } else {
+ sofia_clear_pflag(profile, PFLAG_AUTO_INVITE_100);
+ }
} else {
found = 0;
}
switch_channel_t *channel = NULL;
private_object_t *tech_pvt = NULL;
+ nua_respond(nh, SIP_100_TRYING, TAG_END());
+
if (session) {
channel = switch_core_session_get_channel(session);
tech_pvt = switch_core_session_get_private(session);
return switch_core_session_perform_receive_message(channel->session, &msg, file, func, line);
}
+SWITCH_DECLARE(switch_status_t) switch_channel_perform_acknowledge_call(switch_channel_t *channel,
+ const char *file, const char *func, int line)
+{
+ send_ind(channel, SWITCH_MESSAGE_INDICATE_ACKNOWLEDGE_CALL, file, func, line);
+
+ return SWITCH_STATUS_SUCCESS;
+}
SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_ring_ready_value(switch_channel_t *channel,
switch_ring_ready_t rv,