switch_event_t *end_event;
/** True if ringing event sent to client */
int ringing_sent;
+ /** true if rayo app has started */
+ int rayo_app_started;
+ /** delayed delivery of answer event because rayo APP wasn't started yet */
+ switch_event_t *answer_event;
/** True if request to create this call failed */
int dial_request_failed;
};
if (event) {
switch_event_destroy(&event);
}
+ if (call->answer_event) {
+ switch_event_destroy(&call->answer_event);
+ }
switch_core_hash_destroy(&call->pcps);
}
call->dial_request_id = NULL;
call->end_event = NULL;
call->dial_request_failed = 0;
+ call->rayo_app_started = 0;
+ call->answer_event = NULL;
switch_core_hash_init(&call->pcps);
}
/* check if joining to rayo call */
struct rayo_call *b_call = RAYO_CALL_LOCATE(call_uri);
- if (!b_call) {
- /* not a rayo call */
- response = iks_new_error_detailed(node, STANZA_ERROR_SERVICE_UNAVAILABLE, "b-leg is gone");
- } else if (!has_call_control(b_call, msg)) {
- /* not allowed to join to this call */
- response = iks_new_error(node, STANZA_ERROR_NOT_ALLOWED);
- } else if (b_call->joined) {
- /* don't support multiple joined calls */
- response = iks_new_error_detailed(node, STANZA_ERROR_CONFLICT, "multiple joined calls not supported");
- RAYO_RELEASE(b_call);
- } else {
- /* bridge this call to call-uri */
- switch_channel_set_variable(switch_core_session_get_channel(session), "bypass_media", bypass);
- if (switch_false(bypass)) {
- switch_channel_pre_answer(switch_core_session_get_channel(session));
- }
- 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) {
- iks *request = call->pending_join_request;
- iks *result = iks_new_error(request, STANZA_ERROR_SERVICE_UNAVAILABLE);
- call->pending_join_request = NULL;
- RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
- iks_delete(call->pending_join_request);
+ if (b_call) {
+ if (!call->rayo_app_started) {
+ /* A-leg not under rayo control yet */
+ response = iks_new_error_detailed(node, STANZA_ERROR_UNEXPECTED_REQUEST, "a-leg is not ready to join");
+ } else if (!b_call->rayo_app_started) {
+ /* B-leg not under rayo control yet */
+ response = iks_new_error_detailed(node, STANZA_ERROR_UNEXPECTED_REQUEST, "b-leg is not ready to join");
+ } else if (!has_call_control(b_call, msg)) {
+ /* not allowed to join to this call */
+ response = iks_new_error(node, STANZA_ERROR_NOT_ALLOWED);
+ } else if (b_call->joined) {
+ /* don't support multiple joined calls */
+ response = iks_new_error_detailed(node, STANZA_ERROR_CONFLICT, "multiple joined calls not supported");
+ } else {
+ /* bridge this call to call-uri */
+ switch_channel_set_variable(switch_core_session_get_channel(session), "bypass_media", bypass);
+ if (switch_false(bypass)) {
+ switch_channel_pre_answer(switch_core_session_get_channel(session));
+ }
+ 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) {
+ iks *request = call->pending_join_request;
+ iks *result = iks_new_error(request, STANZA_ERROR_SERVICE_UNAVAILABLE);
+ call->pending_join_request = NULL;
+ RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
+ iks_delete(call->pending_join_request);
+ }
}
RAYO_RELEASE(b_call);
+ } else {
+ /* not a rayo call */
+ response = iks_new_error_detailed(node, STANZA_ERROR_SERVICE_UNAVAILABLE, "b-leg is gone");
}
return response;
}
iks *node = msg->payload;
iks *response = NULL;
- if (call->joined_id) {
+ if (!call->rayo_app_started) {
+ /* A-leg not under rayo control yet */
+ response = iks_new_error_detailed(node, STANZA_ERROR_UNEXPECTED_REQUEST, "call is not ready to join");
+ } else if (call->joined_id) {
/* adjust join conference params */
if (!strcmp("duplex", direction)) {
if ((response = exec_conference_api(session, mixer_name, "unmute", node)) ||
{
struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID"));
if (call) {
- iks *revent = iks_new_presence("answered", RAYO_NS,
- switch_event_get_header(event, "variable_rayo_call_jid"),
- switch_event_get_header(event, "variable_rayo_dcp_jid"));
- RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent);
+ switch_mutex_lock(RAYO_ACTOR(call)->mutex);
+ if (call->rayo_app_started) {
+ iks *revent = iks_new_presence("answered", RAYO_NS,
+ switch_event_get_header(event, "variable_rayo_call_jid"),
+ switch_event_get_header(event, "variable_rayo_dcp_jid"));
+ RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent);
+ } else if (!call->answer_event) {
+ /* delay sending this event until the rayo APP has started */
+ switch_event_dup(&call->answer_event, event);
+ }
+ switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
RAYO_RELEASE(call);
}
}
clients_to_offer_count = switch_separate_string(data_dup, ',', clients_to_offer, sizeof(clients_to_offer) / sizeof(clients_to_offer[0]));
}
+ /* It is now safe for inbound call to be fully controlled by rayo client */
+ if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
+ switch_mutex_lock(RAYO_ACTOR(call)->mutex);
+ call->rayo_app_started = 1;
+ switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
+ }
+
/* Offer call to all (or specified) ONLINE clients */
/* TODO load balance offers so first session doesn't always get offer first? */
switch_mutex_lock(globals.clients_mutex);
switch_channel_set_variable(channel, "hold_hangup_xfer_exten", "park:inline:");
switch_channel_set_variable(channel, SWITCH_SEND_SILENCE_WHEN_IDLE_VARIABLE, "-1"); /* required so that output mixing works */
switch_core_event_hook_add_read_frame(session, rayo_call_on_read_frame);
+
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
+ /* At this point, this outbound call might already be under control of a rayo client that is waiting for answer before sending
+ commands. The answered event might have been sent before we are ready to execute commands, so we delayed sending
+ those events if the rayo APP hadn't started yet. This delay would have only been a few milliseconds.
+ */
+ switch_mutex_lock(RAYO_ACTOR(call)->mutex);
+ call->rayo_app_started = 1;
+ if (call->answer_event) {
+ struct rayo_client *rclient = RAYO_CLIENT(RAYO_LOCATE(rayo_call_get_dcp_jid(call)));
+ if (rclient) {
+ on_call_answer_event(rclient, call->answer_event);
+ switch_event_destroy(&call->answer_event);
+ RAYO_RELEASE(rclient);
+ }
+ }
+ switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
+
+ /* Outbound calls might have a nested join to another call or conference - do that now */
if (!zstr(app)) {
switch_core_session_execute_application(session, app, app_args);
}
}
+
+ /* Ready for remote control */
switch_ivr_park(session, NULL);
}
}