core_unreal.c File Reference

Unreal channel derivatives framework for channel drivers like local channels. More...

#include "asterisk.h"
#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"
#include "asterisk/bridge.h"
#include "asterisk/core_unreal.h"

Include dependency graph for core_unreal.c:

Go to the source code of this file.

Functions

struct ast_unreal_pvtast_unreal_alloc (size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap)
 Allocate the base unreal struct for a derivative.
int ast_unreal_answer (struct ast_channel *ast)
void ast_unreal_call_setup (struct ast_channel *semi1, struct ast_channel *semi2)
 Setup unreal owner and chan channels before initiating call.
int ast_unreal_channel_push_to_bridge (struct ast_channel *ast, struct ast_bridge *bridge, unsigned int flags)
 Push the semi2 unreal channel into a bridge from either member of the unreal pair.
void ast_unreal_destructor (void *vdoomed)
 struct ast_unreal_pvt destructor.
int ast_unreal_digit_begin (struct ast_channel *ast, char digit)
int ast_unreal_digit_end (struct ast_channel *ast, char digit, unsigned int duration)
int ast_unreal_fixup (struct ast_channel *oldchan, struct ast_channel *newchan)
int ast_unreal_hangup (struct ast_unreal_pvt *p, struct ast_channel *ast)
 Hangup one end (maybe both ends) of an unreal channel derivative.
int ast_unreal_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen)
void ast_unreal_lock_all (struct ast_unreal_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
 Send an unreal pvt in with no locks held and get all locks.
struct ast_channelast_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, ast_callid callid)
 Create the semi1 and semi2 unreal channels.
int ast_unreal_queryoption (struct ast_channel *ast, int option, void *data, int *datalen)
struct ast_frameast_unreal_read (struct ast_channel *ast)
int ast_unreal_sendhtml (struct ast_channel *ast, int subclass, const char *data, int datalen)
int ast_unreal_sendtext (struct ast_channel *ast, const char *text)
int ast_unreal_setoption (struct ast_channel *ast, int option, void *data, int datalen)
int ast_unreal_write (struct ast_channel *ast, struct ast_frame *f)
static int got_optimized_out (struct ast_channel *ast, struct ast_unreal_pvt *p)
static int unreal_colp_redirect_indicate (struct ast_unreal_pvt *p, struct ast_channel *ast, int condition)
static int unreal_queue_frame (struct ast_unreal_pvt *p, int isoutbound, struct ast_frame *f, struct ast_channel *us, int us_locked)
 queue a frame onto either the p->owner or p->chan
static int unreal_queue_indicate (struct ast_unreal_pvt *p, struct ast_channel *ast, int condition, const void *data, size_t datalen)

Variables

static unsigned int name_sequence = 0


Detailed Description

Unreal channel derivatives framework for channel drivers like local channels.

Author:
Richard Mudgett <rmudgett@digium.com>
See Also:

Definition in file core_unreal.c.


Function Documentation

struct ast_unreal_pvt* ast_unreal_alloc ( size_t  size,
ao2_destructor_fn  destructor,
struct ast_format_cap cap 
) [read]

Allocate the base unreal struct for a derivative.

Since:
12.0.0
Parameters:
size Size of the unreal struct to allocate.
destructor Destructor callback.
cap Format capabilities to give the unreal private struct.
Return values:
pvt on success.
NULL on error.

Definition at line 891 of file core_unreal.c.

References ao2_alloc, ao2_ref, ast_format_cap_alloc, ast_format_cap_append_from_cap(), AST_FORMAT_CAP_FLAG_DEFAULT, AST_MEDIA_TYPE_UNKNOWN, ast_jb_conf::flags, ast_unreal_pvt::jb_conf, NULL, and ast_unreal_pvt::reqcap.

Referenced by announce_request(), local_alloc(), and media_request_helper().

00892 {
00893    struct ast_unreal_pvt *unreal;
00894 
00895    static const struct ast_jb_conf jb_conf = {
00896       .flags = 0,
00897       .max_size = -1,
00898       .resync_threshold = -1,
00899       .impl = "",
00900       .target_extra = -1,
00901    };
00902 
00903    unreal = ao2_alloc(size, destructor);
00904    if (!unreal) {
00905       return NULL;
00906    }
00907 
00908    unreal->reqcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
00909    if (!unreal->reqcap) {
00910       ao2_ref(unreal, -1);
00911       return NULL;
00912    }
00913    ast_format_cap_append_from_cap(unreal->reqcap, cap, AST_MEDIA_TYPE_UNKNOWN);
00914 
00915    memcpy(&unreal->jb_conf, &jb_conf, sizeof(unreal->jb_conf));
00916 
00917    return unreal;
00918 }

int ast_unreal_answer ( struct ast_channel ast  ) 

Unreal channel framework struct ast_channel_tech.answer callback

Definition at line 255 of file core_unreal.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_channel_name(), ast_channel_tech_pvt(), AST_CONTROL_ANSWER, AST_FRAME_CONTROL, ast_log, AST_UNREAL_IS_OUTBOUND, LOG_WARNING, and unreal_queue_frame().

00256 {
00257    struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
00258    int isoutbound;
00259    int res = -1;
00260 
00261    if (!p) {
00262       return -1;
00263    }
00264 
00265    ao2_ref(p, 1);
00266    ao2_lock(p);
00267    isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
00268    if (isoutbound) {
00269       /* Pass along answer since somebody answered us */
00270       struct ast_frame answer = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
00271 
00272       res = unreal_queue_frame(p, isoutbound, &answer, ast, 1);
00273    } else {
00274       ast_log(LOG_WARNING, "Huh?  %s is being asked to answer?\n",
00275          ast_channel_name(ast));
00276    }
00277    ao2_unlock(p);
00278    ao2_ref(p, -1);
00279    return res;
00280 }

void ast_unreal_call_setup ( struct ast_channel semi1,
struct ast_channel semi2 
)

Setup unreal owner and chan channels before initiating call.

Since:
12.0.0
Parameters:
semi1 Owner channel of unreal channel pair.
semi2 Outgoing channel of unreal channel pair.
Note:
On entry, the semi1 and semi2 channels are already locked.
Returns:
Nothing

Definition at line 657 of file core_unreal.c.

References AST_CAUSE_ANSWERED_ELSEWHERE, ast_channel_accountcode(), ast_channel_caller(), ast_channel_cc_params_init(), ast_channel_connected(), ast_channel_datastore_inherit(), ast_channel_dialed(), ast_channel_get_cc_config_params(), ast_channel_hangupcause(), ast_channel_hangupcause_set(), ast_channel_language(), ast_channel_musicclass(), ast_channel_peeraccount(), ast_channel_publish_varset(), ast_channel_redirecting(), ast_channel_stage_snapshot(), ast_channel_stage_snapshot_done(), ast_channel_varshead(), ast_connected_line_copy_from_caller(), ast_connected_line_copy_to_caller(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_party_dialed_copy(), ast_party_redirecting_copy(), ast_var_assign(), ast_var_full_name(), ast_var_value(), ast_var_t::entries, ast_var_t::name, and ast_var_t::value.

Referenced by local_call().

00658 {
00659    struct ast_var_t *varptr;
00660    struct ast_var_t *clone_var;
00661 
00662    ast_channel_stage_snapshot(semi2);
00663 
00664    /*
00665     * Note that cid_num and cid_name aren't passed in the
00666     * ast_channel_alloc calls in ast_unreal_new_channels().  It's
00667     * done here instead.
00668     */
00669    ast_party_redirecting_copy(ast_channel_redirecting(semi2), ast_channel_redirecting(semi1));
00670 
00671    ast_party_dialed_copy(ast_channel_dialed(semi2), ast_channel_dialed(semi1));
00672 
00673    /* Crossover the CallerID and conected-line to cross the unreal bridge. */
00674    ast_connected_line_copy_to_caller(ast_channel_caller(semi2), ast_channel_connected(semi1));
00675    ast_connected_line_copy_from_caller(ast_channel_connected(semi2), ast_channel_caller(semi1));
00676 
00677    ast_channel_language_set(semi2, ast_channel_language(semi1));
00678 
00679    /* Crossover the accountcode and peeraccount to cross the unreal bridge. */
00680    ast_channel_accountcode_set(semi2, ast_channel_peeraccount(semi1));
00681    ast_channel_peeraccount_set(semi2, ast_channel_accountcode(semi1));
00682 
00683    ast_channel_musicclass_set(semi2, ast_channel_musicclass(semi1));
00684 
00685    ast_channel_cc_params_init(semi2, ast_channel_get_cc_config_params(semi1));
00686 
00687    /*
00688     * Make sure we inherit the AST_CAUSE_ANSWERED_ELSEWHERE if it's
00689     * set on the queue/dial call request in the dialplan.
00690     */
00691    if (ast_channel_hangupcause(semi1) == AST_CAUSE_ANSWERED_ELSEWHERE) {
00692       ast_channel_hangupcause_set(semi2, AST_CAUSE_ANSWERED_ELSEWHERE);
00693    }
00694 
00695    /*
00696     * Copy the channel variables from the semi1 channel to the
00697     * outgoing channel.
00698     *
00699     * Note that due to certain assumptions, they MUST be in the
00700     * same order.
00701     */
00702    AST_LIST_TRAVERSE(ast_channel_varshead(semi1), varptr, entries) {
00703       clone_var = ast_var_assign(varptr->name, varptr->value);
00704       if (clone_var) {
00705          AST_LIST_INSERT_TAIL(ast_channel_varshead(semi2), clone_var, entries);
00706          ast_channel_publish_varset(semi2, ast_var_full_name(clone_var),
00707             ast_var_value(clone_var));
00708       }
00709    }
00710    ast_channel_datastore_inherit(semi1, semi2);
00711 
00712    ast_channel_stage_snapshot_done(semi2);
00713 }

int ast_unreal_channel_push_to_bridge ( struct ast_channel ast,
struct ast_bridge bridge,
unsigned int  flags 
)

Push the semi2 unreal channel into a bridge from either member of the unreal pair.

Since:
12.0.0
Parameters:
ast A member of the unreal channel being pushed
bridge Which bridge we want to push the channel to
flags Feature flags to be set on the bridge channel.
Return values:
0 if the channel is successfully imparted onto the bridge
-1 on failure
Note:
This is equivalent to ast_call() on unreal based channel drivers that are designed to use it instead.

Definition at line 715 of file core_unreal.c.

References ao2_cleanup, ao2_lock, ao2_ref, ao2_unlock, ast_bridge_features_destroy(), ast_bridge_features_new(), ast_bridge_impart(), AST_BRIDGE_IMPART_CHAN_INDEPENDENT, ast_bridge_lock, ast_bridge_unlock, ast_channel_callid(), ast_channel_callid_set(), ast_channel_lock, ast_channel_ref, ast_channel_tech_pvt(), ast_channel_unlock, ast_channel_unref, ast_set_flag, AST_UNREAL_CARETAKER_THREAD, ast_bridge::callid, ast_unreal_pvt::chan, ast_bridge_features::feature_flags, lock, NULL, ast_unreal_pvt::owner, RAII_VAR, SCOPED_AO2LOCK, and SCOPED_CHANNELLOCK.

Referenced by ari_bridges_play_new(), ast_ari_bridges_record(), and bridge_moh_create().

00716 {
00717    struct ast_bridge_features *features;
00718    struct ast_channel *chan;
00719    struct ast_channel *owner;
00720    ast_callid bridge_callid;
00721    RAII_VAR(struct ast_unreal_pvt *, p, NULL, ao2_cleanup);
00722 
00723    ast_bridge_lock(bridge);
00724    bridge_callid = bridge->callid;
00725    ast_bridge_unlock(bridge);
00726 
00727    {
00728       SCOPED_CHANNELLOCK(lock, ast);
00729       p = ast_channel_tech_pvt(ast);
00730       if (!p) {
00731          return -1;
00732       }
00733       ao2_ref(p, +1);
00734    }
00735 
00736    {
00737       SCOPED_AO2LOCK(lock, p);
00738       chan = p->chan;
00739       if (!chan) {
00740          return -1;
00741       }
00742 
00743       owner = p->owner;
00744       if (!owner) {
00745          return -1;
00746       }
00747 
00748       ast_channel_ref(chan);
00749       ast_channel_ref(owner);
00750    }
00751 
00752    if (bridge_callid) {
00753       ast_callid chan_callid;
00754       ast_callid owner_callid;
00755 
00756       /* chan side call ID setting */
00757       ast_channel_lock(chan);
00758 
00759       chan_callid = ast_channel_callid(chan);
00760       if (!chan_callid) {
00761          ast_channel_callid_set(chan, bridge_callid);
00762       }
00763       ast_channel_unlock(chan);
00764 
00765       /* owner side call ID setting */
00766       ast_channel_lock(owner);
00767 
00768       owner_callid = ast_channel_callid(owner);
00769       if (!owner_callid) {
00770          ast_channel_callid_set(owner, bridge_callid);
00771       }
00772 
00773       ast_channel_unlock(owner);
00774    }
00775 
00776    /* We are done with the owner now that its call ID matches the bridge */
00777    ast_channel_unref(owner);
00778    owner = NULL;
00779 
00780    features = ast_bridge_features_new();
00781    if (!features) {
00782       ast_channel_unref(chan);
00783       return -1;
00784    }
00785 
00786    ast_set_flag(&features->feature_flags, flags);
00787 
00788    /* Impart the semi2 channel into the bridge */
00789    if (ast_bridge_impart(bridge, chan, NULL, features,
00790       AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
00791       ast_bridge_features_destroy(features);
00792       ast_channel_unref(chan);
00793       return -1;
00794    }
00795 
00796    ao2_lock(p);
00797    ast_set_flag(p, AST_UNREAL_CARETAKER_THREAD);
00798    ao2_unlock(p);
00799    ast_channel_unref(chan);
00800 
00801    return 0;
00802 }

void ast_unreal_destructor ( void *  vdoomed  ) 

struct ast_unreal_pvt destructor.

Since:
12.0.0
Parameters:
vdoomed Object to destroy.
Returns:
Nothing

Definition at line 883 of file core_unreal.c.

References ao2_cleanup, NULL, and ast_unreal_pvt::reqcap.

Referenced by announce_pvt_destructor(), local_pvt_destructor(), and media_request_helper().

00884 {
00885    struct ast_unreal_pvt *doomed = vdoomed;
00886 
00887    ao2_cleanup(doomed->reqcap);
00888    doomed->reqcap = NULL;
00889 }

int ast_unreal_digit_begin ( struct ast_channel ast,
char  digit 
)

Unreal channel framework struct ast_channel_tech.send_digit_begin callback

Definition at line 566 of file core_unreal.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_channel_tech_pvt(), AST_FRAME_DTMF_BEGIN, AST_UNREAL_IS_OUTBOUND, ast_frame_subclass::integer, ast_frame::subclass, and unreal_queue_frame().

00567 {
00568    struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
00569    int res = -1;
00570    struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00571    int isoutbound;
00572 
00573    if (!p) {
00574       return -1;
00575    }
00576 
00577    ao2_ref(p, 1); /* ref for unreal_queue_frame */
00578    ao2_lock(p);
00579    isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
00580    f.subclass.integer = digit;
00581    res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
00582    ao2_unlock(p);
00583    ao2_ref(p, -1);
00584 
00585    return res;
00586 }

int ast_unreal_digit_end ( struct ast_channel ast,
char  digit,
unsigned int  duration 
)

Unreal channel framework struct ast_channel_tech.send_digit_end callback

Definition at line 588 of file core_unreal.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_channel_tech_pvt(), AST_FRAME_DTMF_END, AST_UNREAL_IS_OUTBOUND, ast_frame_subclass::integer, ast_frame::len, ast_frame::subclass, and unreal_queue_frame().

00589 {
00590    struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
00591    int res = -1;
00592    struct ast_frame f = { AST_FRAME_DTMF_END, };
00593    int isoutbound;
00594 
00595    if (!p) {
00596       return -1;
00597    }
00598 
00599    ao2_ref(p, 1); /* ref for unreal_queue_frame */
00600    ao2_lock(p);
00601    isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
00602    f.subclass.integer = digit;
00603    f.len = duration;
00604    res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
00605    ao2_unlock(p);
00606    ao2_ref(p, -1);
00607 
00608    return res;
00609 }

int ast_unreal_fixup ( struct ast_channel oldchan,
struct ast_channel newchan 
)

Unreal channel framework struct ast_channel_tech.fixup callback

Definition at line 348 of file core_unreal.c.

References ao2_lock, ao2_unlock, ast_channel_internal_bridge(), ast_channel_name(), ast_channel_tech_pvt(), ast_check_hangup(), ast_log, ast_queue_hangup(), ast_unreal_pvt::chan, LOG_WARNING, and ast_unreal_pvt::owner.

00349 {
00350    struct ast_unreal_pvt *p = ast_channel_tech_pvt(newchan);
00351    struct ast_bridge *bridge_owner;
00352    struct ast_bridge *bridge_chan;
00353 
00354    if (!p) {
00355       return -1;
00356    }
00357 
00358    ao2_lock(p);
00359 
00360    if ((p->owner != oldchan) && (p->chan != oldchan)) {
00361       ast_log(LOG_WARNING, "Old channel %p wasn't %p or %p\n", oldchan, p->owner, p->chan);
00362       ao2_unlock(p);
00363       return -1;
00364    }
00365    if (p->owner == oldchan) {
00366       p->owner = newchan;
00367    } else {
00368       p->chan = newchan;
00369    }
00370 
00371    if (ast_check_hangup(newchan) || !p->owner || !p->chan) {
00372       ao2_unlock(p);
00373       return 0;
00374    }
00375 
00376    /* Do not let a masquerade cause an unreal channel to be bridged to itself! */
00377    bridge_owner = ast_channel_internal_bridge(p->owner);
00378    bridge_chan = ast_channel_internal_bridge(p->chan);
00379    if (bridge_owner && bridge_owner == bridge_chan) {
00380       ast_log(LOG_WARNING, "You can not bridge an unreal channel (%s) to itself!\n",
00381          ast_channel_name(newchan));
00382       ao2_unlock(p);
00383       ast_queue_hangup(newchan);
00384       return -1;
00385    }
00386 
00387    ao2_unlock(p);
00388    return 0;
00389 }

int ast_unreal_hangup ( struct ast_unreal_pvt p,
struct ast_channel ast 
)

Hangup one end (maybe both ends) of an unreal channel derivative.

Since:
12.0.0
Parameters:
p Private channel struct (reffed)
ast Channel being hung up. (locked)
Note:
Common hangup code for unreal channels. Derived channels will need to deal with any additional resources.
Return values:
0 on success.
-1 on error.

Definition at line 804 of file core_unreal.c.

References ao2_ref, ao2_unlock, AST_CAUSE_ANSWERED_ELSEWHERE, ast_channel_hangupcause(), ast_channel_hangupcause_set(), ast_channel_lock, ast_channel_name(), ast_channel_tech_pvt_set(), ast_channel_unlock, ast_channel_unref, ast_clear_flag, ast_debug, ast_hangup(), ast_queue_hangup_with_cause(), ast_test_flag, AST_UNREAL_CARETAKER_THREAD, ast_unreal_lock_all(), ast_unreal_pvt::chan, hangup_chan(), NULL, ast_unreal_pvt::owner, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), and status.

Referenced by announce_hangup(), local_hangup(), and media_hangup().

00805 {
00806    int hangup_chan = 0;
00807    int res = 0;
00808    int cause;
00809    struct ast_channel *owner = NULL;
00810    struct ast_channel *chan = NULL;
00811 
00812    /* the pvt isn't going anywhere, it has a ref */
00813    ast_channel_unlock(ast);
00814 
00815    /* lock everything */
00816    ast_unreal_lock_all(p, &chan, &owner);
00817 
00818    if (ast != chan && ast != owner) {
00819       res = -1;
00820       goto unreal_hangup_cleanup;
00821    }
00822 
00823    cause = ast_channel_hangupcause(ast);
00824 
00825    if (ast == p->chan) {
00826       /* Outgoing side is hanging up. */
00827       ast_clear_flag(p, AST_UNREAL_CARETAKER_THREAD);
00828       p->chan = NULL;
00829       if (p->owner) {
00830          const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00831 
00832          if (status) {
00833             ast_channel_hangupcause_set(p->owner, cause);
00834             pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00835          }
00836          ast_queue_hangup_with_cause(p->owner, cause);
00837       }
00838    } else {
00839       /* Owner side is hanging up. */
00840       p->owner = NULL;
00841       if (p->chan) {
00842          if (cause == AST_CAUSE_ANSWERED_ELSEWHERE) {
00843             ast_channel_hangupcause_set(p->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
00844             ast_debug(2, "%s has AST_CAUSE_ANSWERED_ELSEWHERE set.\n",
00845                ast_channel_name(p->chan));
00846          }
00847          if (!ast_test_flag(p, AST_UNREAL_CARETAKER_THREAD)) {
00848             /*
00849              * Need to actually hangup p->chan since nothing else is taking
00850              * care of it.
00851              */
00852             hangup_chan = 1;
00853          } else {
00854             ast_queue_hangup_with_cause(p->chan, cause);
00855          }
00856       }
00857    }
00858 
00859    /* this is one of our locked channels, doesn't matter which */
00860    ast_channel_tech_pvt_set(ast, NULL);
00861    ao2_ref(p, -1);
00862 
00863 unreal_hangup_cleanup:
00864    ao2_unlock(p);
00865    if (owner) {
00866       ast_channel_unlock(owner);
00867       ast_channel_unref(owner);
00868    }
00869    if (chan) {
00870       ast_channel_unlock(chan);
00871       if (hangup_chan) {
00872          ast_hangup(chan);
00873       }
00874       ast_channel_unref(chan);
00875    }
00876 
00877    /* leave with the channel locked that came in */
00878    ast_channel_lock(ast);
00879 
00880    return res;
00881 }

int ast_unreal_indicate ( struct ast_channel ast,
int  condition,
const void *  data,
size_t  datalen 
)

Unreal channel framework struct ast_channel_tech.indicate callback

Definition at line 521 of file core_unreal.c.

References ao2_ref, ast_channel_tech_pvt(), AST_CONTROL_CONNECTED_LINE, AST_CONTROL_HOLD, AST_CONTROL_MASQUERADE_NOTIFY, AST_CONTROL_REDIRECTING, AST_CONTROL_UNHOLD, ast_moh_start(), ast_moh_stop(), ast_test_flag, AST_UNREAL_MOH_INTERCEPT, NULL, unreal_colp_redirect_indicate(), and unreal_queue_indicate().

00522 {
00523    struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
00524    int res = 0;
00525 
00526    if (!p) {
00527       return -1;
00528    }
00529 
00530    ao2_ref(p, 1); /* ref for unreal_queue_frame */
00531 
00532    switch (condition) {
00533    case AST_CONTROL_MASQUERADE_NOTIFY:
00534       /*
00535        * Always block this because this is the channel being
00536        * masqueraded; not anything down the chain.
00537        */
00538       break;
00539    case AST_CONTROL_CONNECTED_LINE:
00540    case AST_CONTROL_REDIRECTING:
00541       res = unreal_colp_redirect_indicate(p, ast, condition);
00542       break;
00543    case AST_CONTROL_HOLD:
00544       if (ast_test_flag(p, AST_UNREAL_MOH_INTERCEPT)) {
00545          ast_moh_start(ast, data, NULL);
00546          break;
00547       }
00548       res = unreal_queue_indicate(p, ast, condition, data, datalen);
00549       break;
00550    case AST_CONTROL_UNHOLD:
00551       if (ast_test_flag(p, AST_UNREAL_MOH_INTERCEPT)) {
00552          ast_moh_stop(ast);
00553          break;
00554       }
00555       res = unreal_queue_indicate(p, ast, condition, data, datalen);
00556       break;
00557    default:
00558       res = unreal_queue_indicate(p, ast, condition, data, datalen);
00559       break;
00560    }
00561 
00562    ao2_ref(p, -1);
00563    return res;
00564 }

void ast_unreal_lock_all ( struct ast_unreal_pvt p,
struct ast_channel **  outchan,
struct ast_channel **  outowner 
)

Send an unreal pvt in with no locks held and get all locks.

Note:
NO locks should be held prior to calling this function

The pvt must have a ref held before calling this function

if outchan or outowner is set != NULL after calling this function those channels are locked and reffed.

Batman.

Definition at line 48 of file core_unreal.c.

References ao2_lock, ao2_unlock, ast_channel_lock, ast_channel_lock_both, ast_channel_ref, ast_channel_unlock, ast_channel_unref, ast_unreal_pvt::chan, NULL, and ast_unreal_pvt::owner.

Referenced by ast_unreal_hangup(), local_call(), publish_local_bridge_message(), stasis_app_channel_unreal_set_internal(), and unreal_colp_redirect_indicate().

00049 {
00050    struct ast_channel *chan = NULL;
00051    struct ast_channel *owner = NULL;
00052 
00053    ao2_lock(p);
00054    for (;;) {
00055       if (p->chan) {
00056          chan = p->chan;
00057          ast_channel_ref(chan);
00058       }
00059       if (p->owner) {
00060          owner = p->owner;
00061          ast_channel_ref(owner);
00062       }
00063       ao2_unlock(p);
00064 
00065       /* if we don't have both channels, then this is very easy */
00066       if (!owner || !chan) {
00067          if (owner) {
00068             ast_channel_lock(owner);
00069          } else if(chan) {
00070             ast_channel_lock(chan);
00071          }
00072       } else {
00073          /* lock both channels first, then get the pvt lock */
00074          ast_channel_lock_both(chan, owner);
00075       }
00076       ao2_lock(p);
00077 
00078       /* Now that we have all the locks, validate that nothing changed */
00079       if (p->owner != owner || p->chan != chan) {
00080          if (owner) {
00081             ast_channel_unlock(owner);
00082             owner = ast_channel_unref(owner);
00083          }
00084          if (chan) {
00085             ast_channel_unlock(chan);
00086             chan = ast_channel_unref(chan);
00087          }
00088          continue;
00089       }
00090 
00091       break;
00092    }
00093    *outowner = p->owner;
00094    *outchan = p->chan;
00095 }

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,
ast_callid  callid 
) [read]

Create the semi1 and semi2 unreal channels.

Since:
12.0.0
Parameters:
p Unreal channel private struct.
tech Channel technology to use.
semi1_state State to start the semi1(owner) channel in.
semi2_state State to start the semi2(outgoing chan) channel in.
exten Exten to start the chennels in. (NULL if s)
context Context to start the channels in. (NULL if default)
requestor Channel requesting creation. (NULL if none)
callid Thread callid to use.
Return values:
semi1_channel on success.
NULL on error.

Definition at line 920 of file core_unreal.c.

References ao2_cleanup, ao2_ref, ast_alloca, ast_atomic_fetchadd_int(), ast_channel_alloc, ast_channel_callid_set(), ast_channel_cc_params_init(), ast_channel_flags(), ast_channel_get_cc_config_params(), ast_channel_nativeformats_set(), ast_channel_release(), ast_channel_set_rawreadformat(), ast_channel_set_rawwriteformat(), ast_channel_set_readformat(), ast_channel_set_writeformat(), ast_channel_tech_pvt_set(), ast_channel_tech_set(), ast_channel_unlock, AST_FLAG_DISABLE_DEVSTATE_CACHE, ast_format_cap_get_format(), ast_jb_configure(), ast_log, ast_set_flag, ast_strlen_zero, ast_unreal_pvt::chan, ast_unreal_pvt::jb_conf, LOG_WARNING, ast_unreal_pvt::name, NULL, ast_unreal_pvt::owner, RAII_VAR, ast_unreal_pvt::reqcap, ast_channel_tech::type, ast_assigned_ids::uniqueid, and ast_assigned_ids::uniqueid2.

Referenced by announce_request(), local_request(), and media_request_helper().

00924 {
00925    struct ast_channel *owner;
00926    struct ast_channel *chan;
00927    RAII_VAR(struct ast_format *, fmt, NULL, ao2_cleanup);
00928    struct ast_assigned_ids id1 = {NULL, NULL};
00929    struct ast_assigned_ids id2 = {NULL, NULL};
00930    int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1);
00931 
00932    /* set unique ids for the two channels */
00933    if (assignedids && !ast_strlen_zero(assignedids->uniqueid)) {
00934       id1.uniqueid = assignedids->uniqueid;
00935       id2.uniqueid = assignedids->uniqueid2;
00936    }
00937 
00938    /* if id1 given but not id2, use default of id1;2 */
00939    if (id1.uniqueid && ast_strlen_zero(id2.uniqueid)) {
00940       char *uniqueid2;
00941 
00942       uniqueid2 = ast_alloca(strlen(id1.uniqueid) + 3);
00943       strcpy(uniqueid2, id1.uniqueid);/* Safe */
00944       strcat(uniqueid2, ";2");/* Safe */
00945       id2.uniqueid = uniqueid2;
00946    }
00947 
00948    /*
00949     * Allocate two new Asterisk channels
00950     *
00951     * Make sure that the ;2 channel gets the same linkedid as ;1.
00952     * You can't pass linkedid to both allocations since if linkedid
00953     * isn't set, then each channel will generate its own linkedid.
00954     */
00955    owner = ast_channel_alloc(1, semi1_state, NULL, NULL, NULL,
00956       exten, context, &id1, requestor, 0,
00957       "%s/%s-%08x;1", tech->type, p->name, (unsigned)generated_seqno);
00958    if (!owner) {
00959       ast_log(LOG_WARNING, "Unable to allocate owner channel structure\n");
00960       return NULL;
00961    }
00962 
00963    if (callid) {
00964       ast_channel_callid_set(owner, callid);
00965    }
00966 
00967    ast_channel_tech_set(owner, tech);
00968    ao2_ref(p, +1);
00969    ast_channel_tech_pvt_set(owner, p);
00970 
00971    ast_channel_nativeformats_set(owner, p->reqcap);
00972 
00973    /* Determine our read/write format and set it on each channel */
00974    fmt = ast_format_cap_get_format(p->reqcap, 0);
00975    if (!fmt) {
00976       ast_channel_tech_pvt_set(owner, NULL);
00977       ao2_ref(p, -1);
00978       ast_channel_unlock(owner);
00979       ast_channel_release(owner);
00980       return NULL;
00981    }
00982 
00983    ast_channel_set_writeformat(owner, fmt);
00984    ast_channel_set_rawwriteformat(owner, fmt);
00985    ast_channel_set_readformat(owner, fmt);
00986    ast_channel_set_rawreadformat(owner, fmt);
00987 
00988    ast_set_flag(ast_channel_flags(owner), AST_FLAG_DISABLE_DEVSTATE_CACHE);
00989 
00990    ast_jb_configure(owner, &p->jb_conf);
00991 
00992    if (ast_channel_cc_params_init(owner, requestor
00993       ? ast_channel_get_cc_config_params((struct ast_channel *) requestor) : NULL)) {
00994       ast_channel_tech_pvt_set(owner, NULL);
00995       ao2_ref(p, -1);
00996       ast_channel_tech_pvt_set(owner, NULL);
00997       ast_channel_unlock(owner);
00998       ast_channel_release(owner);
00999       return NULL;
01000    }
01001 
01002    p->owner = owner;
01003    ast_channel_unlock(owner);
01004 
01005    chan = ast_channel_alloc(1, semi2_state, NULL, NULL, NULL,
01006       exten, context, &id2, owner, 0,
01007       "%s/%s-%08x;2", tech->type, p->name, (unsigned)generated_seqno);
01008    if (!chan) {
01009       ast_log(LOG_WARNING, "Unable to allocate chan channel structure\n");
01010       ast_channel_tech_pvt_set(owner, NULL);
01011       ao2_ref(p, -1);
01012       ast_channel_tech_pvt_set(owner, NULL);
01013       ast_channel_release(owner);
01014       return NULL;
01015    }
01016 
01017    if (callid) {
01018       ast_channel_callid_set(chan, callid);
01019    }
01020 
01021    ast_channel_tech_set(chan, tech);
01022    ao2_ref(p, +1);
01023    ast_channel_tech_pvt_set(chan, p);
01024 
01025    ast_channel_nativeformats_set(chan, p->reqcap);
01026 
01027    /* Format was already determined when setting up owner */
01028    ast_channel_set_writeformat(chan, fmt);
01029    ast_channel_set_rawwriteformat(chan, fmt);
01030    ast_channel_set_readformat(chan, fmt);
01031    ast_channel_set_rawreadformat(chan, fmt);
01032 
01033    ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE);
01034 
01035    p->chan = chan;
01036    ast_channel_unlock(chan);
01037 
01038    return owner;
01039 }

int ast_unreal_queryoption ( struct ast_channel ast,
int  option,
void *  data,
int *  datalen 
)

Unreal channel framework struct ast_channel_tech.queryoption callback

Definition at line 167 of file core_unreal.c.

References ao2_lock, ao2_unlock, ast_channel_bridge_peer(), ast_channel_lock, ast_channel_queryoption(), ast_channel_ref, ast_channel_tech_pvt(), ast_channel_unlock, ast_channel_unref, AST_OPTION_T38_STATE, AST_UNREAL_IS_OUTBOUND, ast_unreal_pvt::chan, and ast_unreal_pvt::owner.

00168 {
00169    struct ast_unreal_pvt *p;
00170    struct ast_channel *peer;
00171    struct ast_channel *other;
00172    int res = 0;
00173 
00174    if (option != AST_OPTION_T38_STATE) {
00175       /* AST_OPTION_T38_STATE is the only supported option at this time */
00176       return -1;
00177    }
00178 
00179    /* for some reason the channel is not locked in channel.c when this function is called */
00180    if (!(p = ast_channel_tech_pvt(ast))) {
00181       return -1;
00182    }
00183 
00184    ao2_lock(p);
00185    other = AST_UNREAL_IS_OUTBOUND(ast, p) ? p->owner : p->chan;
00186    if (!other) {
00187       ao2_unlock(p);
00188       return -1;
00189    }
00190    ast_channel_ref(other);
00191    ao2_unlock(p);
00192    ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
00193 
00194    peer = ast_channel_bridge_peer(other);
00195    if (peer) {
00196       res = ast_channel_queryoption(peer, option, data, datalen, 0);
00197       ast_channel_unref(peer);
00198    }
00199    ast_channel_unref(other);
00200    ast_channel_lock(ast); /* Lock back before we leave */
00201 
00202    return res;
00203 }

struct ast_frame* ast_unreal_read ( struct ast_channel ast  )  [read]

Unreal channel framework struct ast_channel_tech.read and struct ast_channel_tech.exception callback

Definition at line 314 of file core_unreal.c.

References ast_null_frame.

00315 {
00316    return &ast_null_frame;
00317 }

int ast_unreal_sendhtml ( struct ast_channel ast,
int  subclass,
const char *  data,
int  datalen 
)

Unreal channel framework struct ast_channel_tech.send_html callback

Definition at line 633 of file core_unreal.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_channel_tech_pvt(), AST_FRAME_HTML, AST_UNREAL_IS_OUTBOUND, ast_frame::data, ast_frame::datalen, ast_frame_subclass::integer, ast_frame::ptr, ast_frame::subclass, and unreal_queue_frame().

00634 {
00635    struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
00636    int res = -1;
00637    struct ast_frame f = { AST_FRAME_HTML, };
00638    int isoutbound;
00639 
00640    if (!p) {
00641       return -1;
00642    }
00643 
00644    ao2_ref(p, 1); /* ref for unreal_queue_frame */
00645    ao2_lock(p);
00646    isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
00647    f.subclass.integer = subclass;
00648    f.data.ptr = (char *)data;
00649    f.datalen = datalen;
00650    res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
00651    ao2_unlock(p);
00652    ao2_ref(p, -1);
00653 
00654    return res;
00655 }

int ast_unreal_sendtext ( struct ast_channel ast,
const char *  text 
)

Unreal channel framework struct ast_channel_tech.send_text callback

Definition at line 611 of file core_unreal.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_channel_tech_pvt(), AST_FRAME_TEXT, AST_UNREAL_IS_OUTBOUND, ast_frame::data, ast_frame::datalen, ast_frame::ptr, and unreal_queue_frame().

00612 {
00613    struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
00614    int res = -1;
00615    struct ast_frame f = { AST_FRAME_TEXT, };
00616    int isoutbound;
00617 
00618    if (!p) {
00619       return -1;
00620    }
00621 
00622    ao2_ref(p, 1); /* ref for unreal_queue_frame */
00623    ao2_lock(p);
00624    isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
00625    f.data.ptr = (char *) text;
00626    f.datalen = strlen(text) + 1;
00627    res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
00628    ao2_unlock(p);
00629    ao2_ref(p, -1);
00630    return res;
00631 }

int ast_unreal_setoption ( struct ast_channel chan,
int  option,
void *  data,
int  datalen 
)

Unreal channel framework struct ast_channel_tech.setoption callback

Definition at line 98 of file core_unreal.c.

References ao2_lock, ao2_ref, ao2_unlock, AST_CHAN_WRITE_INFO_T_VERSION, ast_channel_lock, ast_channel_ref, ast_channel_tech_pvt(), ast_channel_unlock, ast_channel_unref, ast_log, AST_OPTION_CHANNEL_WRITE, ast_unreal_pvt::chan, ast_chan_write_info_t::chan, ast_chan_write_info_t::data, ast_chan_write_info_t::function, LOG_ERROR, NULL, ast_unreal_pvt::owner, ast_chan_write_info_t::value, ast_chan_write_info_t::version, and ast_chan_write_info_t::write_fn.

00099 {
00100    int res = 0;
00101    struct ast_unreal_pvt *p;
00102    struct ast_channel *otherchan = NULL;
00103    ast_chan_write_info_t *write_info;
00104    char *info_data;
00105 
00106    if (option != AST_OPTION_CHANNEL_WRITE) {
00107       return -1;
00108    }
00109 
00110    write_info = data;
00111 
00112    if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
00113       ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
00114       return -1;
00115    }
00116 
00117    info_data = write_info->data;
00118    if (!strcmp(write_info->function, "CHANNEL")) {
00119       if (!strncasecmp(info_data, "hangup_handler_", 15)) {
00120          /* Block CHANNEL(hangup_handler_xxx) writes to the other unreal channel. */
00121          return 0;
00122       }
00123 
00124       /* Crossover the accountcode and peeraccount to cross the unreal bridge. */
00125       if (!strcasecmp(info_data, "accountcode")) {
00126          info_data = "peeraccount";
00127       } else if (!strcasecmp(info_data, "peeraccount")) {
00128          info_data = "accountcode";
00129       }
00130    }
00131 
00132    /* get the tech pvt */
00133    if (!(p = ast_channel_tech_pvt(ast))) {
00134       return -1;
00135    }
00136    ao2_ref(p, 1);
00137    ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
00138 
00139    /* get the channel we are supposed to write to */
00140    ao2_lock(p);
00141    otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
00142    if (!otherchan || otherchan == write_info->chan) {
00143       res = -1;
00144       otherchan = NULL;
00145       ao2_unlock(p);
00146       goto setoption_cleanup;
00147    }
00148    ast_channel_ref(otherchan);
00149 
00150    /* clear the pvt lock before grabbing the channel */
00151    ao2_unlock(p);
00152 
00153    ast_channel_lock(otherchan);
00154    res = write_info->write_fn(otherchan, write_info->function, info_data, write_info->value);
00155    ast_channel_unlock(otherchan);
00156 
00157 setoption_cleanup:
00158    ao2_ref(p, -1);
00159    if (otherchan) {
00160       ast_channel_unref(otherchan);
00161    }
00162    ast_channel_lock(ast); /* Lock back before we leave */
00163    return res;
00164 }

int ast_unreal_write ( struct ast_channel ast,
struct ast_frame f 
)

Unreal channel framework struct ast_channel_tech.write callback

Definition at line 319 of file core_unreal.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_channel_tech_pvt(), AST_FRAME_VIDEO, AST_FRAME_VOICE, AST_UNREAL_IS_OUTBOUND, ast_frame::frametype, got_optimized_out(), and unreal_queue_frame().

00320 {
00321    struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
00322    int res = -1;
00323 
00324    if (!p) {
00325       return -1;
00326    }
00327 
00328    /* Just queue for delivery to the other side */
00329    ao2_ref(p, 1);
00330    ao2_lock(p);
00331    switch (f->frametype) {
00332    case AST_FRAME_VOICE:
00333    case AST_FRAME_VIDEO:
00334       if (got_optimized_out(ast, p)) {
00335          break;
00336       }
00337       /* fall through */
00338    default:
00339       res = unreal_queue_frame(p, AST_UNREAL_IS_OUTBOUND(ast, p), f, ast, 1);
00340       break;
00341    }
00342    ao2_unlock(p);
00343    ao2_ref(p, -1);
00344 
00345    return res;
00346 }

static int got_optimized_out ( struct ast_channel ast,
struct ast_unreal_pvt p 
) [static]

Definition at line 296 of file core_unreal.c.

References ast_bridge_unreal_optimize_out(), ast_test_flag, AST_UNREAL_NO_OPTIMIZATION, ast_unreal_pvt::chan, and ast_unreal_pvt::owner.

Referenced by ast_unreal_write().

00297 {
00298    int res = 0;
00299 
00300    /* Do a few conditional checks early on just to see if this optimization is possible */
00301    if (ast_test_flag(p, AST_UNREAL_NO_OPTIMIZATION) || !p->chan || !p->owner) {
00302       return res;
00303    }
00304 
00305    if (ast == p->owner) {
00306       res = ast_bridge_unreal_optimize_out(p->owner, p->chan, p);
00307    } else if (ast == p->chan) {
00308       res = ast_bridge_unreal_optimize_out(p->chan, p->owner, p);
00309    }
00310 
00311    return res;
00312 }

static int unreal_colp_redirect_indicate ( struct ast_unreal_pvt p,
struct ast_channel ast,
int  condition 
) [static]

Definition at line 456 of file core_unreal.c.

References ao2_unlock, ast_channel_caller(), ast_channel_connected(), ast_channel_lock, ast_channel_redirecting(), ast_channel_unlock, ast_channel_unref, ast_connected_line_build_data(), ast_connected_line_copy_to_caller(), AST_CONTROL_CONNECTED_LINE, AST_FRAME_CONTROL, ast_redirecting_build_data(), AST_UNREAL_IS_OUTBOUND, ast_unreal_lock_all(), ast_unreal_pvt::chan, ast_frame::datalen, ast_frame::frametype, NULL, ast_unreal_pvt::owner, and unreal_queue_frame().

Referenced by ast_unreal_indicate().

00457 {
00458    struct ast_channel *my_chan;
00459    struct ast_channel *my_owner;
00460    struct ast_channel *this_channel;
00461    struct ast_channel *the_other_channel;
00462    int isoutbound;
00463    int res = 0;
00464    unsigned char frame_data[1024];
00465    struct ast_frame f = {
00466       .frametype = AST_FRAME_CONTROL,
00467       .subclass.integer = condition,
00468       .data.ptr = frame_data,
00469    };
00470 
00471    /*
00472     * A connected line update frame may only contain a partial
00473     * amount of data, such as just a source, or just a ton, and not
00474     * the full amount of information.  However, the collected
00475     * information is all stored in the outgoing channel's
00476     * connectedline structure, so when receiving a connected line
00477     * update on an outgoing unreal channel, we need to transmit the
00478     * collected connected line information instead of whatever
00479     * happens to be in this control frame.  The same applies for
00480     * redirecting information, which is why it is handled here as
00481     * well.
00482     */
00483    ast_channel_unlock(ast);
00484    ast_unreal_lock_all(p, &my_chan, &my_owner);
00485    isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
00486    if (isoutbound) {
00487       this_channel = p->chan;
00488       the_other_channel = p->owner;
00489    } else {
00490       this_channel = p->owner;
00491       the_other_channel = p->chan;
00492    }
00493    if (the_other_channel) {
00494       if (condition == AST_CONTROL_CONNECTED_LINE) {
00495          ast_connected_line_copy_to_caller(ast_channel_caller(the_other_channel),
00496             ast_channel_connected(this_channel));
00497          f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data),
00498             ast_channel_connected(this_channel), NULL);
00499       } else {
00500          f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data),
00501             ast_channel_redirecting(this_channel), NULL);
00502       }
00503    }
00504    if (my_chan) {
00505       ast_channel_unlock(my_chan);
00506       ast_channel_unref(my_chan);
00507    }
00508    if (my_owner) {
00509       ast_channel_unlock(my_owner);
00510       ast_channel_unref(my_owner);
00511    }
00512    if (the_other_channel) {
00513       res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
00514    }
00515    ao2_unlock(p);
00516    ast_channel_lock(ast);
00517 
00518    return res;
00519 }

static int unreal_queue_frame ( struct ast_unreal_pvt p,
int  isoutbound,
struct ast_frame f,
struct ast_channel us,
int  us_locked 
) [static]

queue a frame onto either the p->owner or p->chan

Note:
the ast_unreal_pvt MUST have it's ref count bumped before entering this function and decremented after this function is called. This is a side effect of the deadlock avoidance that is necessary to lock 2 channels and a tech_pvt. Without a ref counted ast_unreal_pvt, it is impossible to guarantee it will not be destroyed by another thread during deadlock avoidance.

Definition at line 214 of file core_unreal.c.

References ao2_lock, ao2_unlock, ast_channel_generator(), ast_channel_lock, ast_channel_ref, ast_channel_unlock, ast_channel_unref, AST_CONTROL_RINGING, AST_FRAME_CONTROL, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_queue_frame(), ast_setstate(), AST_STATE_RINGING, ast_unreal_pvt::chan, ast_frame::frametype, ast_frame_subclass::integer, ast_unreal_pvt::owner, and ast_frame::subclass.

Referenced by ast_unreal_answer(), ast_unreal_digit_begin(), ast_unreal_digit_end(), ast_unreal_sendhtml(), ast_unreal_sendtext(), ast_unreal_write(), unreal_colp_redirect_indicate(), and unreal_queue_indicate().

00216 {
00217    struct ast_channel *other;
00218 
00219    /* Recalculate outbound channel */
00220    other = isoutbound ? p->owner : p->chan;
00221    if (!other) {
00222       return 0;
00223    }
00224 
00225    /* do not queue media frames if a generator is on both unreal channels */
00226    if (us
00227       && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)
00228       && ast_channel_generator(us)
00229       && ast_channel_generator(other)) {
00230       return 0;
00231    }
00232 
00233    /* grab a ref on the channel before unlocking the pvt,
00234     * other can not go away from us now regardless of locking */
00235    ast_channel_ref(other);
00236    if (us && us_locked) {
00237       ast_channel_unlock(us);
00238    }
00239    ao2_unlock(p);
00240 
00241    if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) {
00242       ast_setstate(other, AST_STATE_RINGING);
00243    }
00244    ast_queue_frame(other, f);
00245 
00246    other = ast_channel_unref(other);
00247    if (us && us_locked) {
00248       ast_channel_lock(us);
00249    }
00250    ao2_lock(p);
00251 
00252    return 0;
00253 }

static int unreal_queue_indicate ( struct ast_unreal_pvt p,
struct ast_channel ast,
int  condition,
const void *  data,
size_t  datalen 
) [static]

Definition at line 406 of file core_unreal.c.

References ao2_lock, ao2_unlock, AST_CONTROL_T38_PARAMETERS, ast_debug, AST_FRAME_CONTROL, AST_T38_REQUEST_PARMS, ast_test_flag, AST_UNREAL_IS_OUTBOUND, AST_UNREAL_NO_OPTIMIZATION, ast_frame::frametype, ast_control_t38_parameters::request_response, and unreal_queue_frame().

Referenced by ast_unreal_indicate().

00407 {
00408    int res = 0;
00409    int isoutbound;
00410 
00411    ao2_lock(p);
00412    /*
00413     * Block -1 stop tones events if we are to be optimized out.  We
00414     * don't need a flurry of these events on an unreal channel chain
00415     * when initially connected to slow the optimization process.
00416     */
00417    if (0 <= condition || ast_test_flag(p, AST_UNREAL_NO_OPTIMIZATION)) {
00418       struct ast_frame f = {
00419          .frametype = AST_FRAME_CONTROL,
00420          .subclass.integer = condition,
00421          .data.ptr = (void *) data,
00422          .datalen = datalen,
00423       };
00424 
00425       isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
00426       res = unreal_queue_frame(p, isoutbound, &f, ast, 1);
00427       if (!res
00428          && condition == AST_CONTROL_T38_PARAMETERS
00429          && datalen == sizeof(struct ast_control_t38_parameters)) {
00430          const struct ast_control_t38_parameters *parameters = data;
00431 
00432          if (parameters->request_response == AST_T38_REQUEST_PARMS) {
00433             res = AST_T38_REQUEST_PARMS;
00434          }
00435       }
00436    } else {
00437       ast_debug(4, "Blocked indication %d\n", condition);
00438    }
00439    ao2_unlock(p);
00440 
00441    return res;
00442 }


Variable Documentation

unsigned int name_sequence = 0 [static]

Definition at line 46 of file core_unreal.c.


Generated on Thu Apr 16 06:30:31 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6