Merge "core/frame: Fix ast_frdup() and ast_frisolate() for empty text frames"
[asterisk/asterisk.git] / main / core_unreal.c
index 481ed2d..763be4f 100644 (file)
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
 #include "asterisk/causes.h"
 #include "asterisk/channel.h"
+#include "asterisk/stasis_channels.h"
 #include "asterisk/pbx.h"
 #include "asterisk/musiconhold.h"
 #include "asterisk/astobj2.h"
@@ -100,6 +99,7 @@ int ast_unreal_setoption(struct ast_channel *ast, int option, void *data, int da
        struct ast_unreal_pvt *p;
        struct ast_channel *otherchan = NULL;
        ast_chan_write_info_t *write_info;
+       char *info_data;
 
        if (option != AST_OPTION_CHANNEL_WRITE) {
                return -1;
@@ -112,10 +112,19 @@ int ast_unreal_setoption(struct ast_channel *ast, int option, void *data, int da
                return -1;
        }
 
-       if (!strcmp(write_info->function, "CHANNEL")
-               && !strncasecmp(write_info->data, "hangup_handler_", 15)) {
-               /* Block CHANNEL(hangup_handler_xxx) writes to the other unreal channel. */
-               return 0;
+       info_data = write_info->data;
+       if (!strcmp(write_info->function, "CHANNEL")) {
+               if (!strncasecmp(info_data, "hangup_handler_", 15)) {
+                       /* Block CHANNEL(hangup_handler_xxx) writes to the other unreal channel. */
+                       return 0;
+               }
+
+               /* Crossover the accountcode and peeraccount to cross the unreal bridge. */
+               if (!strcasecmp(info_data, "accountcode")) {
+                       info_data = "peeraccount";
+               } else if (!strcasecmp(info_data, "peeraccount")) {
+                       info_data = "accountcode";
+               }
        }
 
        /* get the tech pvt */
@@ -140,7 +149,7 @@ int ast_unreal_setoption(struct ast_channel *ast, int option, void *data, int da
        ao2_unlock(p);
 
        ast_channel_lock(otherchan);
-       res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value);
+       res = write_info->write_fn(otherchan, write_info->function, info_data, write_info->value);
        ast_channel_unlock(otherchan);
 
 setoption_cleanup:
@@ -314,6 +323,20 @@ int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f)
                return -1;
        }
 
+       /* If we are told to write a frame with a type that has no corresponding
+        * stream on the channel then drop it.
+        */
+       if (f->frametype == AST_FRAME_VOICE) {
+               if (!ast_channel_get_default_stream(ast, AST_MEDIA_TYPE_AUDIO)) {
+                       return 0;
+               }
+       } else if (f->frametype == AST_FRAME_VIDEO ||
+               (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_VIDUPDATE)) {
+               if (!ast_channel_get_default_stream(ast, AST_MEDIA_TYPE_VIDEO)) {
+                       return 0;
+               }
+       }
+
        /* Just queue for delivery to the other side */
        ao2_ref(p, 1);
        ao2_lock(p);
@@ -519,6 +542,12 @@ int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data
        ao2_ref(p, 1); /* ref for unreal_queue_frame */
 
        switch (condition) {
+       case AST_CONTROL_MASQUERADE_NOTIFY:
+               /*
+                * Always block this because this is the channel being
+                * masqueraded; not anything down the chain.
+                */
+               break;
        case AST_CONTROL_CONNECTED_LINE:
        case AST_CONTROL_REDIRECTING:
                res = unreal_colp_redirect_indicate(p, ast, condition);
@@ -537,6 +566,23 @@ int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data
                }
                res = unreal_queue_indicate(p, ast, condition, data, datalen);
                break;
+       case AST_CONTROL_RINGING:
+               /* Don't queue ringing frames if the channel is not in a "ring" state. Otherwise,
+                * the real channel on the other end will likely start a playtones generator. It is
+                * possible that this playtones generator will never be stopped under certain
+                * circumstances.
+                */
+               if (ast_channel_state(ast) == AST_STATE_RING) {
+                       res = unreal_queue_indicate(p, ast, condition, data, datalen);
+               } else {
+                       res = -1;
+               }
+               break;
+       case AST_CONTROL_PVT_CAUSE_CODE:
+               /* Return -1 so that asterisk core will correctly set up hangupcauses. */
+               unreal_queue_indicate(p, ast, condition, data, datalen);
+               res = -1;
+               break;
        default:
                res = unreal_queue_indicate(p, ast, condition, data, datalen);
                break;
@@ -642,6 +688,8 @@ void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2)
        struct ast_var_t *varptr;
        struct ast_var_t *clone_var;
 
+       ast_channel_stage_snapshot(semi2);
+
        /*
         * Note that cid_num and cid_name aren't passed in the
         * ast_channel_alloc calls in ast_unreal_new_channels().  It's
@@ -651,12 +699,17 @@ void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2)
 
        ast_party_dialed_copy(ast_channel_dialed(semi2), ast_channel_dialed(semi1));
 
+       /* Crossover the CallerID and conected-line to cross the unreal bridge. */
        ast_connected_line_copy_to_caller(ast_channel_caller(semi2), ast_channel_connected(semi1));
        ast_connected_line_copy_from_caller(ast_channel_connected(semi2), ast_channel_caller(semi1));
 
        ast_channel_language_set(semi2, ast_channel_language(semi1));
-       ast_channel_accountcode_set(semi2, ast_channel_accountcode(semi1));
        ast_channel_musicclass_set(semi2, ast_channel_musicclass(semi1));
+       ast_channel_parkinglot_set(semi2, ast_channel_parkinglot(semi1));
+
+       /* Crossover the accountcode and peeraccount to cross the unreal bridge. */
+       ast_channel_accountcode_set(semi2, ast_channel_peeraccount(semi1));
+       ast_channel_peeraccount_set(semi2, ast_channel_accountcode(semi1));
 
        ast_channel_cc_params_init(semi2, ast_channel_get_cc_config_params(semi1));
 
@@ -679,9 +732,13 @@ void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2)
                clone_var = ast_var_assign(varptr->name, varptr->value);
                if (clone_var) {
                        AST_LIST_INSERT_TAIL(ast_channel_varshead(semi2), clone_var, entries);
+                       ast_channel_publish_varset(semi2, ast_var_full_name(clone_var),
+                               ast_var_value(clone_var));
                }
        }
        ast_channel_datastore_inherit(semi1, semi2);
+
+       ast_channel_stage_snapshot_done(semi2);
 }
 
 int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge *bridge, unsigned int flags)
@@ -689,12 +746,11 @@ int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge
        struct ast_bridge_features *features;
        struct ast_channel *chan;
        struct ast_channel *owner;
+       ast_callid bridge_callid;
        RAII_VAR(struct ast_unreal_pvt *, p, NULL, ao2_cleanup);
 
-       RAII_VAR(struct ast_callid *, bridge_callid, NULL, ast_callid_cleanup);
-
        ast_bridge_lock(bridge);
-       bridge_callid = bridge->callid ? ast_callid_ref(bridge->callid) : NULL;
+       bridge_callid = bridge->callid;
        ast_bridge_unlock(bridge);
 
        {
@@ -723,8 +779,8 @@ int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge
        }
 
        if (bridge_callid) {
-               struct ast_callid *chan_callid;
-               struct ast_callid *owner_callid;
+               ast_callid chan_callid;
+               ast_callid owner_callid;
 
                /* chan side call ID setting */
                ast_channel_lock(chan);
@@ -734,7 +790,6 @@ int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge
                        ast_channel_callid_set(chan, bridge_callid);
                }
                ast_channel_unlock(chan);
-               ast_callid_cleanup(chan_callid);
 
                /* owner side call ID setting */
                ast_channel_lock(owner);
@@ -745,7 +800,6 @@ int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge
                }
 
                ast_channel_unlock(owner);
-               ast_callid_cleanup(owner_callid);
        }
 
        /* We are done with the owner now that its call ID matches the bridge */
@@ -763,14 +817,15 @@ int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge
        /* Impart the semi2 channel into the bridge */
        if (ast_bridge_impart(bridge, chan, NULL, features,
                AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
-               ast_bridge_features_destroy(features);
                ast_channel_unref(chan);
                return -1;
        }
 
+       /* The bridge thread now controls the chan ref from the ast_unreal_pvt */
        ao2_lock(p);
        ast_set_flag(p, AST_UNREAL_CARETAKER_THREAD);
        ao2_unlock(p);
+
        ast_channel_unref(chan);
 
        return 0;
@@ -859,7 +914,8 @@ void ast_unreal_destructor(void *vdoomed)
 {
        struct ast_unreal_pvt *doomed = vdoomed;
 
-       doomed->reqcap = ast_format_cap_destroy(doomed->reqcap);
+       ao2_cleanup(doomed->reqcap);
+       doomed->reqcap = NULL;
 }
 
 struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap)
@@ -878,11 +934,13 @@ struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructo
        if (!unreal) {
                return NULL;
        }
-       unreal->reqcap = ast_format_cap_dup(cap);
+
+       unreal->reqcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
        if (!unreal->reqcap) {
                ao2_ref(unreal, -1);
                return NULL;
        }
+       ast_format_cap_append_from_cap(unreal->reqcap, cap, AST_MEDIA_TYPE_UNKNOWN);
 
        memcpy(&unreal->jb_conf, &jb_conf, sizeof(unreal->jb_conf));
 
@@ -892,11 +950,11 @@ struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructo
 struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
        const struct ast_channel_tech *tech, int semi1_state, int semi2_state,
        const char *exten, const char *context, const struct ast_assigned_ids *assignedids,
-       const struct ast_channel *requestor, struct ast_callid *callid)
+       const struct ast_channel *requestor, ast_callid callid)
 {
        struct ast_channel *owner;
        struct ast_channel *chan;
-       struct ast_format fmt;
+       RAII_VAR(struct ast_format *, fmt, NULL, ao2_cleanup);
        struct ast_assigned_ids id1 = {NULL, NULL};
        struct ast_assigned_ids id2 = {NULL, NULL};
        int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1);
@@ -911,7 +969,7 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
        if (id1.uniqueid && ast_strlen_zero(id2.uniqueid)) {
                char *uniqueid2;
 
-               uniqueid2 = ast_alloca(strlen(id1.uniqueid) + 2);
+               uniqueid2 = ast_alloca(strlen(id1.uniqueid) + 3);
                strcpy(uniqueid2, id1.uniqueid);/* Safe */
                strcat(uniqueid2, ";2");/* Safe */
                id2.uniqueid = uniqueid2;
@@ -924,9 +982,10 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
         * You can't pass linkedid to both allocations since if linkedid
         * isn't set, then each channel will generate its own linkedid.
         */
-       if (!(owner = ast_channel_alloc(1, semi1_state, NULL, NULL, NULL,
-                       exten, context, &id1, requestor, 0,
-                       "%s/%s-%08x;1", tech->type, p->name, (unsigned)generated_seqno))) {
+       owner = ast_channel_alloc(1, semi1_state, NULL, NULL, NULL,
+               exten, context, &id1, requestor, 0,
+               "%s/%s-%08x;1", tech->type, p->name, (unsigned)generated_seqno);
+       if (!owner) {
                ast_log(LOG_WARNING, "Unable to allocate owner channel structure\n");
                return NULL;
        }
@@ -939,14 +998,22 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
        ao2_ref(p, +1);
        ast_channel_tech_pvt_set(owner, p);
 
-       ast_format_cap_copy(ast_channel_nativeformats(owner), p->reqcap);
+       ast_channel_nativeformats_set(owner, p->reqcap);
 
        /* Determine our read/write format and set it on each channel */
-       ast_best_codec(p->reqcap, &fmt);
-       ast_format_copy(ast_channel_writeformat(owner), &fmt);
-       ast_format_copy(ast_channel_rawwriteformat(owner), &fmt);
-       ast_format_copy(ast_channel_readformat(owner), &fmt);
-       ast_format_copy(ast_channel_rawreadformat(owner), &fmt);
+       fmt = ast_format_cap_get_format(p->reqcap, 0);
+       if (!fmt) {
+               ast_channel_tech_pvt_set(owner, NULL);
+               ao2_ref(p, -1);
+               ast_channel_unlock(owner);
+               ast_channel_release(owner);
+               return NULL;
+       }
+
+       ast_channel_set_writeformat(owner, fmt);
+       ast_channel_set_rawwriteformat(owner, fmt);
+       ast_channel_set_readformat(owner, fmt);
+       ast_channel_set_rawreadformat(owner, fmt);
 
        ast_set_flag(ast_channel_flags(owner), AST_FLAG_DISABLE_DEVSTATE_CACHE);
 
@@ -954,6 +1021,7 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
 
        if (ast_channel_cc_params_init(owner, requestor
                ? ast_channel_get_cc_config_params((struct ast_channel *) requestor) : NULL)) {
+               ast_channel_tech_pvt_set(owner, NULL);
                ao2_ref(p, -1);
                ast_channel_tech_pvt_set(owner, NULL);
                ast_channel_unlock(owner);
@@ -964,10 +1032,12 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
        p->owner = owner;
        ast_channel_unlock(owner);
 
-       if (!(chan = ast_channel_alloc(1, semi2_state, NULL, NULL, NULL,
-                       exten, context, &id2, owner, 0,
-                       "%s/%s-%08x;2", tech->type, p->name, (unsigned)generated_seqno))) {
+       chan = ast_channel_alloc(1, semi2_state, NULL, NULL, NULL,
+               exten, context, &id2, owner, 0,
+               "%s/%s-%08x;2", tech->type, p->name, (unsigned)generated_seqno);
+       if (!chan) {
                ast_log(LOG_WARNING, "Unable to allocate chan channel structure\n");
+               ast_channel_tech_pvt_set(owner, NULL);
                ao2_ref(p, -1);
                ast_channel_tech_pvt_set(owner, NULL);
                ast_channel_release(owner);
@@ -982,13 +1052,13 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
        ao2_ref(p, +1);
        ast_channel_tech_pvt_set(chan, p);
 
-       ast_format_cap_copy(ast_channel_nativeformats(chan), p->reqcap);
+       ast_channel_nativeformats_set(chan, p->reqcap);
 
        /* Format was already determined when setting up owner */
-       ast_format_copy(ast_channel_writeformat(chan), &fmt);
-       ast_format_copy(ast_channel_rawwriteformat(chan), &fmt);
-       ast_format_copy(ast_channel_readformat(chan), &fmt);
-       ast_format_copy(ast_channel_rawreadformat(chan), &fmt);
+       ast_channel_set_writeformat(chan, fmt);
+       ast_channel_set_rawwriteformat(chan, fmt);
+       ast_channel_set_readformat(chan, fmt);
+       ast_channel_set_rawreadformat(chan, fmt);
 
        ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE);