]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-5865 --resolve mod_rayo: fix join/unjoin IQ result for mixers
authorChris Rienzo <chris.rienzo@grasshopper.com>
Tue, 15 Oct 2013 18:17:33 +0000 (14:17 -0400)
committerChris Rienzo <chris.rienzo@grasshopper.com>
Tue, 15 Oct 2013 18:17:33 +0000 (14:17 -0400)
src/mod/event_handlers/mod_rayo/mod_rayo.c

index 92257aa2f6edd1c232ecb60701a24099141feff4..df1ce007c9f3247c24fdef7526428f0f07c4cb1d 100644 (file)
@@ -941,10 +941,11 @@ static void rayo_call_cleanup(struct rayo_actor *actor)
 
        /* lost the race: pending join failed... send IQ result to client now. */
        if (call->pending_join_request) {
-               iks *result = iks_new_error_detailed(call->pending_join_request, STANZA_ERROR_ITEM_NOT_FOUND, "call ended");
-               RAYO_SEND_REPLY(call, iks_find_attrib_soft(call->pending_join_request, "from"), result);
-               iks_delete(call->pending_join_request);
+               iks *request = call->pending_join_request;
+               iks *result = iks_new_error_detailed(request, STANZA_ERROR_ITEM_NOT_FOUND, "call ended");
                call->pending_join_request = NULL;
+               RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
+               iks_delete(call->pending_join_request);
        }
 
        iks_delete(revent);
@@ -1765,9 +1766,11 @@ static iks *join_call(struct rayo_call *call, switch_core_session_t *session, st
                }
                call->pending_join_request = iks_copy(node);
                if (switch_ivr_uuid_bridge(rayo_call_get_uuid(call), rayo_call_get_uuid(b_call)) != SWITCH_STATUS_SUCCESS) {
-                       response = iks_new_error_detailed(node, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to bridge call");
-                       iks_delete(call->pending_join_request);
+                       iks *request = call->pending_join_request;
+                       iks *result = iks_new_error_detailed(request, STANZA_ERROR_ITEM_NOT_FOUND, "failed to bridge call");
                        call->pending_join_request = NULL;
+                       RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
+                       iks_delete(call->pending_join_request);
                }
                RAYO_UNLOCK(b_call);
        }
@@ -1776,14 +1779,66 @@ static iks *join_call(struct rayo_call *call, switch_core_session_t *session, st
 
 /**
  * Execute command on session's conference
+ * @param session to execute conference API on
+ * @param conf_name of conference
+ * @param command to send to conference
+ * @param node IQ request
+ * @return response on failure
  */
-static void exec_conference_api(switch_core_session_t *session, const char *conf_name, const char *command)
+static iks *exec_conference_api(switch_core_session_t *session, const char *conf_name, const char *command, iks *node)
 {
+       iks *response = NULL;
        switch_stream_handle_t stream = { 0 };
        const char *conf_member_id = switch_channel_get_variable(switch_core_session_get_channel(session), "conference_member_id");
        SWITCH_STANDARD_STREAM(stream);
        switch_api_execute("conference", switch_core_session_sprintf(session, "%s %s %s", conf_name, command, conf_member_id), NULL, &stream);
+       if (!zstr(stream.data) && strncmp("OK", stream.data, 2)) {
+               response = iks_new_error_detailed_printf(node, STANZA_ERROR_INTERNAL_SERVER_ERROR, "%s", stream.data);
+       }
        switch_safe_free(stream.data);
+       return response;
+}
+
+/**
+ * Execute conference app on session
+ * @param session to execute conference API on
+ * @param command to send to conference (conference name, member flags, etc)
+ * @param node IQ request
+ * @return response on failure
+ */
+static iks *exec_conference_app(switch_core_session_t *session, const char *command, iks *node)
+{
+       iks *response = NULL;
+       switch_event_t *execute_event = NULL;
+       switch_channel_t *channel = switch_core_session_get_channel(session);
+
+       /* conference requires local media on channel */
+       if (!switch_channel_media_ready(channel) && switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
+               /* shit */
+               response = iks_new_error_detailed(node, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to start media");
+               return response;
+       }
+
+       /* send execute conference event to session */
+       if (switch_event_create(&execute_event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) {
+               switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "call-command", "execute");
+               switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-name", "conference");
+               switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", command);
+               //switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event_uuid", uuid);
+               switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event-lock", "true");
+               if (!switch_channel_test_flag(channel, CF_PROXY_MODE)) {
+                       switch_channel_set_flag(channel, CF_BLOCK_BROADCAST_UNTIL_MEDIA);
+               }
+
+               if (switch_core_session_queue_private_event(session, &execute_event, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
+                       response = iks_new_error_detailed(node, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to join mixer (queue event failed)");
+                       if (execute_event) {
+                               switch_event_destroy(&execute_event);
+                       }
+                       return response;
+               }
+       }
+       return response;
 }
 
 /**
@@ -1803,14 +1858,20 @@ static iks *join_mixer(struct rayo_call *call, switch_core_session_t *session, s
        if (call->joined_id) {
                /* adjust join conference params */
                if (!strcmp("duplex", direction)) {
-                       exec_conference_api(session, mixer_name, "unmute");
-                       exec_conference_api(session, mixer_name, "undeaf");
+                       if ((response = exec_conference_api(session, mixer_name, "unmute", node)) ||
+                               (response = exec_conference_api(session, mixer_name, "undeaf", node))) {
+                               return response;
+                       }
                } else if (!strcmp("recv", direction)) {
-                       exec_conference_api(session, mixer_name, "mute");
-                       exec_conference_api(session, mixer_name, "undeaf");
+                       if ((response = exec_conference_api(session, mixer_name, "mute", node)) ||
+                               (response = exec_conference_api(session, mixer_name, "undeaf", node))) {
+                               return response;
+                       }
                } else {
-                       exec_conference_api(session, mixer_name, "unmute");
-                       exec_conference_api(session, mixer_name, "deaf");
+                       if ((response = exec_conference_api(session, mixer_name, "unmute", node)) ||
+                               (response = exec_conference_api(session, mixer_name, "deaf", node))) {
+                               return response;
+                       }
                }
                response = iks_new_iq_result(node);
        } else {
@@ -1821,10 +1882,12 @@ static iks *join_mixer(struct rayo_call *call, switch_core_session_t *session, s
                } else if (!strcmp("recv", direction)) {
                        conf_args = switch_core_session_sprintf(session, "%s+flags{mute}", conf_args);
                }
-               if (switch_core_session_execute_application_async(session, "conference", conf_args) == SWITCH_STATUS_SUCCESS) {
-                       response = iks_new_iq_result(node);
-               } else {
-                       response = iks_new_error_detailed(node, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed execute conference app");
+
+               call->pending_join_request = iks_copy(node);
+               response = exec_conference_app(session, conf_args, node);
+               if (response) {
+                       iks_delete(call->pending_join_request);
+                       call->pending_join_request = NULL;
                }
        }
        return response;
@@ -1951,11 +2014,12 @@ static iks *unjoin_mixer(struct rayo_call *call, switch_core_session_t *session,
                goto done;
        }
 
-       /* ack command */
-       response = iks_new_iq_result(node);
-
        /* kick the member */
-       exec_conference_api(session, mixer_name, "hup");
+       response = exec_conference_api(session, mixer_name, "hup", node);
+       if (!response) {
+               /* ack command */
+               response = iks_new_iq_result(node);
+       }
 
 done:
 
@@ -2538,6 +2602,15 @@ static void on_mixer_add_member_event(struct rayo_mixer *mixer, switch_event_t *
                call->joined = JOINED_MIXER;
                call->joined_id = switch_core_strdup(RAYO_POOL(call), rayo_mixer_get_name(mixer));
 
+               /* send IQ result to client now. */
+               if (call->pending_join_request) {
+                       iks *request = call->pending_join_request;
+                       iks *result = iks_new_iq_result(request);
+                       call->pending_join_request = NULL;
+                       RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
+                       iks_delete(request);
+               }
+
                /* send mixer joined event to member DCP */
                add_member_event = iks_new_presence("joined", RAYO_NS, RAYO_JID(call), call->dcp_jid);
                x = iks_find(add_member_event, "joined");
@@ -2705,14 +2778,13 @@ static void on_call_bridge_event(struct rayo_client *rclient, switch_event_t *ev
                call->joined_id = switch_core_strdup(RAYO_POOL(call), b_uuid);
 
                /* send IQ result to client now. */
-               switch_mutex_lock(RAYO_ACTOR(call)->mutex);
                if (call->pending_join_request) {
-                       iks *result = iks_new_iq_result(call->pending_join_request);
-                       RAYO_SEND_REPLY(call, iks_find_attrib_soft(call->pending_join_request, "from"), result);
-                       iks_delete(call->pending_join_request);
+                       iks *request = call->pending_join_request;
+                       iks *result = iks_new_iq_result(request);
                        call->pending_join_request = NULL;
+                       RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
+                       iks_delete(request);
                }
-               switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
 
                /* send A-leg event */
                revent = iks_new_presence("joined", RAYO_NS,
@@ -2760,14 +2832,13 @@ static void on_call_unbridge_event(struct rayo_client *rclient, switch_event_t *
                call->joined_id = NULL;
 
                /* send IQ result to client now. */
-               switch_mutex_lock(RAYO_ACTOR(call)->mutex);
                if (call->pending_join_request) {
-                       iks *result = iks_new_iq_result(call->pending_join_request);
-                       RAYO_SEND_REPLY(call, iks_find_attrib_soft(call->pending_join_request, "from"), result);
-                       iks_delete(call->pending_join_request);
+                       iks *request = call->pending_join_request;
+                       iks *result = iks_new_iq_result(request);
                        call->pending_join_request = NULL;
+                       RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
+                       iks_delete(request);
                }
-               switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
 
                /* send A-leg event */
                revent = iks_new_presence("unjoined", RAYO_NS,
@@ -2793,6 +2864,36 @@ static void on_call_unbridge_event(struct rayo_client *rclient, switch_event_t *
        }
 }
 
+/**
+ * Handle call execute application event
+ * @param rclient the Rayo client
+ * @param event the execute event
+ */
+static void on_call_execute_event(struct rayo_client *rclient, switch_event_t *event)
+{
+       struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID"));
+       if (call) {
+               switch_log_printf(SWITCH_CHANNEL_UUID_LOG(RAYO_ID(call)), SWITCH_LOG_DEBUG, "Application %s execute\n", switch_event_get_header(event, "Application"));
+               RAYO_UNLOCK(call);
+       }
+}
+
+/**
+ * Handle call execute application complete event
+ * @param rclient the Rayo client
+ * @param event the execute complete event
+ */
+static void on_call_execute_complete_event(struct rayo_client *rclient, switch_event_t *event)
+{
+       struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID"));
+       if (call) {
+               const char *app = switch_event_get_header(event, "Application");
+               switch_log_printf(SWITCH_CHANNEL_UUID_LOG(RAYO_ID(call)), SWITCH_LOG_DEBUG, "Application %s execute complete: %s \n",
+                       app,
+                       switch_event_get_header(event, "Application-Response"));
+               RAYO_UNLOCK(call);
+       }
+}
 
 /**
  * Handle events to deliver to client connection
@@ -2819,6 +2920,12 @@ static void rayo_client_handle_event(struct rayo_client *rclient, switch_event_t
                case SWITCH_EVENT_CHANNEL_UNBRIDGE:
                        on_call_unbridge_event(rclient, event);
                        break;
+               case SWITCH_EVENT_CHANNEL_EXECUTE:
+                       on_call_execute_event(rclient, event);
+                       break;
+               case SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE:
+                       on_call_execute_complete_event(rclient, event);
+                       break;
                default:
                        /* don't care */
                        break;
@@ -2944,7 +3051,9 @@ static switch_status_t rayo_call_on_read_frame(switch_core_session_t *session, s
                switch_time_t idle_start = call->idle_start_time;
                int idle_duration_ms = (now - idle_start) / 1000;
                /* detect idle session (rayo-client has stopped controlling call) and terminate call */
-               if (!rayo_call_is_joined(call) && idle_duration_ms > globals.max_idle_ms) {
+               if (rayo_call_is_joined(call)) {
+                       call->idle_start_time = now;
+               } else if (idle_duration_ms > globals.max_idle_ms) {
                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Ending abandoned call.  idle_duration_ms = %i ms\n", idle_duration_ms);
                        switch_channel_hangup(channel, RAYO_CAUSE_HANGUP);
                }
@@ -3891,6 +4000,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_rayo_load)
        switch_event_bind(modname, SWITCH_EVENT_CHANNEL_ANSWER, NULL, route_call_event, NULL);
        switch_event_bind(modname, SWITCH_EVENT_CHANNEL_BRIDGE, NULL, route_call_event, NULL);
        switch_event_bind(modname, SWITCH_EVENT_CHANNEL_UNBRIDGE, NULL, route_call_event, NULL);
+       switch_event_bind(modname, SWITCH_EVENT_CHANNEL_EXECUTE, NULL, route_call_event, NULL);
+       switch_event_bind(modname, SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE, NULL, route_call_event, NULL);
 
        switch_event_bind(modname, SWITCH_EVENT_CHANNEL_DESTROY, NULL, on_call_end_event, NULL);