From 387fdc5311b8b910ce61f466df7e7b940aa94e32 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 12 Sep 2006 22:24:39 +0000 Subject: [PATCH] add justinu's patch git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2670 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- .../mod_conference/mod_conference.c | 49 +++++-- src/mod/endpoints/mod_sofia/mod_sofia.c | 122 +++++++++++++++++- src/switch_core.c | 2 +- 3 files changed, 154 insertions(+), 19 deletions(-) diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 74db3e4bc3..241949768d 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -80,7 +80,8 @@ typedef enum { CFLAG_DYNAMIC = (1 << 1), CFLAG_ENFORCE_MIN = (1 << 2), CFLAG_DESTRUCT = (1 << 3), - CFLAG_LOCKED = (1 << 4) + CFLAG_LOCKED = (1 << 4), + CFLAG_ANSWERED = (1 << 5) } conf_flag_t; typedef enum { @@ -127,6 +128,7 @@ struct conference_obj { char *bad_pin_sound; char *profile_name; uint32_t flags; + switch_call_cause_t bridge_hangup_cause; switch_mutex_t *flag_mutex; uint32_t rate; uint32_t interval; @@ -645,7 +647,13 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v for(imember = conference->members; imember; imember = imember->next) { switch_channel_t *channel = switch_core_session_get_channel(imember->session); - switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + // add this little bit to preserve the bridge cause code in case of an early media call that + // never answers + if (switch_test_flag(conference, CFLAG_ANSWERED)) + switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + else + // put actual cause code from outbound channel hangup here + switch_channel_hangup(channel, conference->bridge_hangup_cause); switch_clear_flag_locked(imember, MFLAG_RUNNING); } @@ -698,12 +706,6 @@ static void conference_loop(conference_member_t *member) return; } - if (!switch_channel_test_flag(channel, CF_OUTBOUND)) { - /* Answer the channel */ - switch_channel_answer(channel); - } - - /* Prepare the write frame */ write_frame.data = data; write_frame.buflen = sizeof(data); write_frame.codec = &member->write_codec; @@ -723,7 +725,20 @@ static void conference_loop(conference_member_t *member) if (switch_core_session_dequeue_event(member->session, &event) == SWITCH_STATUS_SUCCESS) { switch_event_destroy(&event); } - +#if 1 + if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + // test to see if outbound channel has answered + if (switch_channel_test_flag(channel, CF_ANSWERED) && !switch_test_flag(member->conference, CFLAG_ANSWERED)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Outbound conference channel answered, setting CFLAG_ANSWERED"); + switch_set_flag(member->conference, CFLAG_ANSWERED); + } + } else { + if (switch_test_flag(member->conference, CFLAG_ANSWERED) && !switch_channel_test_flag(channel, CF_ANSWERED)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CLFAG_ANSWERED set, answering inbound channel\n"); + switch_channel_answer(channel); + } + } +#endif if (switch_channel_has_dtmf(channel)) { switch_channel_dequeue_dtmf(channel, dtmf, sizeof(dtmf)); @@ -946,6 +961,15 @@ static void conference_loop(conference_member_t *member) switch_clear_flag_locked(member, MFLAG_RUNNING); switch_core_timer_destroy(&timer); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel leaving conference, cause: %s\n", + switch_channel_cause2str(switch_channel_get_cause(channel))); + + // if it's an outbound channel, store the release cause in the conference struct, we might need it + if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + member->conference->bridge_hangup_cause = switch_channel_get_cause(channel); + } + /* Wait for the input thead to end */ while(switch_test_flag(member, MFLAG_ITHREAD)) { switch_yield(1000); @@ -2055,7 +2079,8 @@ static switch_status_t conference_outcall(conference_obj_t *conference, cid_name, cid_num, NULL) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create Outgoing Channel!\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot create outgoing channel, cause: %s\n", + switch_channel_cause2str(cause)); if (session) { caller_channel = switch_core_session_get_channel(session); switch_channel_hangup(caller_channel, cause); @@ -2319,7 +2344,9 @@ static void conference_function(switch_core_session_t *session, char *data) if (conference_outcall(conference, session, bridgeto, 60, NULL, NULL, NULL) != SWITCH_STATUS_SUCCESS) { goto done; } - } + } //else + // if we're not using "bridge:" set the conference answered flag + //switch_set_flag(conference, CFLAG_ANSWERED); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 19bb50bc88..84c16bff7a 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -532,14 +532,69 @@ static switch_status_t sofia_on_execute(switch_core_session_t *session) return SWITCH_STATUS_SUCCESS; } +// map QSIG cause codes to SIP ala RFC4497 +static int hangup_cause_to_sip(switch_call_cause_t cause) { + switch (cause) { + case SWITCH_CAUSE_UNALLOCATED: + case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET: + case SWITCH_CAUSE_NO_ROUTE_DESTINATION: + return 404; + case SWITCH_CAUSE_USER_BUSY: + return 486; + case SWITCH_CAUSE_NO_USER_RESPONSE: + return 408; + case SWITCH_CAUSE_NO_ANSWER: + return 480; + case SWITCH_CAUSE_CALL_REJECTED: + return 603; + case SWITCH_CAUSE_NUMBER_CHANGED: + return 410; + case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER: + return 502; + case SWITCH_CAUSE_INVALID_NUMBER_FORMAT: + return 484; + case SWITCH_CAUSE_FACILITY_REJECTED: + return 501; + case SWITCH_CAUSE_NORMAL_UNSPECIFIED: + return 480; + case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION: + case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER: + case SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE: + case SWITCH_CAUSE_SWITCH_CONGESTION: + return 503; + case SWITCH_CAUSE_OUTGOING_CALL_BARRED: + case SWITCH_CAUSE_INCOMING_CALL_BARRED: + case SWITCH_CAUSE_BEARERCAPABILITY_NOTAUTH: + return 403; + case SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL: + return 503; + case SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL: + return 488; + case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED: + return 501; + case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION: + return 503; + case SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE: + return 504; + default: + return 500; + } + +} + static switch_status_t sofia_on_hangup(switch_core_session_t *session) { private_object_t *tech_pvt; switch_channel_t *channel = NULL; + switch_call_cause_t cause; + int sip_cause; channel = switch_core_session_get_channel(session); assert(channel != NULL); + cause = switch_channel_get_cause(channel); + sip_cause = hangup_cause_to_sip(cause); + tech_pvt = (private_object_t *) switch_core_session_get_private(session); assert(tech_pvt != NULL); @@ -547,14 +602,18 @@ static switch_status_t sofia_on_hangup(switch_core_session_t *session) su_home_deinit(tech_pvt->home); - + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel %s hanging up, cause: %s, SIP response: %d\n", + switch_channel_get_name(channel), switch_channel_cause2str(cause), sip_cause); if (tech_pvt->nh) { if (!switch_test_flag(tech_pvt, TFLAG_BYE)) { if (switch_test_flag(tech_pvt, TFLAG_ANS)) { nua_bye(tech_pvt->nh, TAG_END()); } else { - nua_cancel(tech_pvt->nh, TAG_END()); + if (switch_test_flag(tech_pvt, TFLAG_INBOUND)) + nua_respond(tech_pvt->nh, sip_cause, NULL, TAG_END()); + else + nua_cancel(tech_pvt->nh, TAG_END()); } } nua_handle_bind(tech_pvt->nh, NULL); @@ -565,8 +624,6 @@ static switch_status_t sofia_on_hangup(switch_core_session_t *session) switch_set_flag_locked(tech_pvt, TFLAG_BYE); switch_clear_flag_locked(tech_pvt, TFLAG_IO); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA HANGUP\n"); - return SWITCH_STATUS_SUCCESS; } @@ -1198,6 +1255,57 @@ static uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t *sdp) return match; } +// map sip responses to QSIG cause codes ala RFC4497 +static switch_call_cause_t sip_cause_to_freeswitch(int status) { + switch (status) { + case 200: + return SWITCH_CAUSE_NORMAL_CLEARING; + case 401: + case 402: + case 403: + case 407: + case 603: + return SWITCH_CAUSE_CALL_REJECTED; + case 404: + case 485: + case 604: + return SWITCH_CAUSE_UNALLOCATED; + case 408: + case 504: + return SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE; + case 410: + return SWITCH_CAUSE_NUMBER_CHANGED; + case 413: + case 414: + case 416: + case 420: + case 421: + case 423: + case 505: + case 513: + return SWITCH_CAUSE_INTERWORKING; + case 480: + return SWITCH_CAUSE_NO_USER_RESPONSE; + case 400: + case 481: + case 500: + case 503: + return SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE; + case 486: + case 600: + return SWITCH_CAUSE_USER_BUSY; + case 484: + return SWITCH_CAUSE_INVALID_NUMBER_FORMAT; + case 488: + case 606: + return SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL; + case 502: + return SWITCH_CAUSE_NETWORK_OUT_OF_ORDER; + default: + return SWITCH_CAUSE_NORMAL_UNSPECIFIED; + } +} + static void sip_i_state(int status, char const *phrase, nua_t *nua, @@ -1362,7 +1470,7 @@ static void sip_i_state(int status, case nua_callstate_terminated: if (session) { switch_set_flag_locked(tech_pvt, TFLAG_BYE); - terminate_session(&session, SWITCH_CAUSE_NORMAL_CLEARING, __LINE__); + terminate_session(&session, sip_cause_to_freeswitch(status), __LINE__); } break; } @@ -1445,8 +1553,8 @@ static void event_callback(nua_event_t event, tagi_t tags[]) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "event [%s] status [%d] [%s]\n", - nua_event_name (event), status, phrase); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "channel [%s] event [%s] status [%d] [%s]\n", + session ? switch_channel_get_name(switch_core_session_get_channel(session)) : "null",nua_event_name (event), status, phrase); switch (event) { case nua_r_shutdown: diff --git a/src/switch_core.c b/src/switch_core.c index c7db02a095..8e7ba0ff92 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -2372,7 +2372,7 @@ static void switch_core_standard_on_init(switch_core_session_t *session) static void switch_core_standard_on_hangup(switch_core_session_t *session) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard HANGUP %s\n", switch_channel_get_name(session->channel)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard HANGUP %s, cause: %s\n", switch_channel_get_name(session->channel),switch_channel_cause2str(switch_channel_get_cause(session->channel))); }