]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
add justinu's patch
authorAnthony Minessale <anthony.minessale@gmail.com>
Tue, 12 Sep 2006 22:24:39 +0000 (22:24 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Tue, 12 Sep 2006 22:24:39 +0000 (22:24 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2670 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/mod/applications/mod_conference/mod_conference.c
src/mod/endpoints/mod_sofia/mod_sofia.c
src/switch_core.c

index 74db3e4bc33d4c65ad8a421a59b3d6650dacbb10..241949768d0bcc4a2916fe667989296e84aadc2b 100644 (file)
@@ -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);
 
 
 
index 19bb50bc889ca41ff7d2fd71b7c0bf2ee121bfce..84c16bff7a39a5894f40d350380fb05088ecdae4 100644 (file)
@@ -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:    
index c7db02a095f4fd53e72434e50b953389c91411ef..8e7ba0ff92d9a9a38f245e018caa3efdcc2b127e 100644 (file)
@@ -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)));
 
 }