static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) { struct local_pvt *p = ast_channel_tech_pvt(newchan); if (!p) { return -1; } ao2_lock(p); if ((p->owner != oldchan) && (p->chan != oldchan)) { ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); ao2_unlock(p); return -1; } if (p->owner == oldchan) { p->owner = newchan; } else { p->chan = newchan; } /* Do not let a masquerade cause a Local channel to be bridged to itself! */ if (!ast_check_hangup(newchan) && ((p->owner && ast_channel_internal_bridged_channel(p->owner) == p->chan) || (p->chan && ast_channel_internal_bridged_channel(p->chan) == p->owner))) { ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n"); ao2_unlock(p); ast_queue_hangup(newchan); return -1; } ao2_unlock(p); return 0; }
static int manager_optimize_away(struct mansession *s, const struct message *m) { const char *channel; struct local_pvt *p; struct local_pvt *found; struct ast_channel *chan; channel = astman_get_header(m, "Channel"); if (ast_strlen_zero(channel)) { astman_send_error(s, m, "'Channel' not specified."); return 0; } chan = ast_channel_get_by_name(channel); if (!chan) { astman_send_error(s, m, "Channel does not exist."); return 0; } p = ast_channel_tech_pvt(chan); ast_channel_unref(chan); found = p ? ao2_find(locals, p, 0) : NULL; if (found) { ao2_lock(found); ast_clear_flag(&found->base, AST_UNREAL_NO_OPTIMIZATION); ao2_unlock(found); ao2_ref(found, -1); astman_send_ack(s, m, "Queued channel to be optimized away"); } else { astman_send_error(s, m, "Unable to find channel"); } return 0; }
static int local_write(struct ast_channel *ast, struct ast_frame *f) { struct local_pvt *p = ast_channel_tech_pvt(ast); int res = -1; int isoutbound; if (!p) { return -1; } /* Just queue for delivery to the other side */ ao2_ref(p, 1); /* ref for local_queue_frame */ ao2_lock(p); isoutbound = IS_OUTBOUND(ast, p); if (isoutbound && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) { check_bridge(ast, p); } if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) { res = local_queue_frame(p, isoutbound, f, ast, 1); } else { ast_debug(1, "Not posting to '%s' queue since already masqueraded out\n", ast_channel_name(ast)); res = 0; } ao2_unlock(p); ao2_ref(p, -1); return res; }
int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f) { struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast); int res = -1; if (!p) { return -1; } /* Just queue for delivery to the other side */ ao2_ref(p, 1); ao2_lock(p); switch (f->frametype) { case AST_FRAME_VOICE: case AST_FRAME_VIDEO: if (got_optimized_out(ast, p)) { break; } /* fall through */ default: res = unreal_queue_frame(p, AST_UNREAL_IS_OUTBOUND(ast, p), f, ast, 1); break; } ao2_unlock(p); ao2_ref(p, -1); return res; }
int ast_local_setup_masquerade(struct ast_channel *ast, struct ast_channel *masq) { struct local_pvt *p; struct local_pvt *found; int res = -1; /* Sanity checks. */ if (!ast || !masq) { return -1; } ast_channel_lock(ast); p = ast_channel_tech_pvt(ast); ast_channel_unlock(ast); found = p ? ao2_find(locals, p, 0) : NULL; if (found) { ao2_lock(found); if (found->type == LOCAL_CALL_ACTION_DIALPLAN && found->base.owner && found->base.chan && !ast_test_flag(&found->base, AST_UNREAL_CARETAKER_THREAD)) { ast_channel_ref(masq); found->type = LOCAL_CALL_ACTION_MASQUERADE; found->action.masq = masq; res = 0; } ao2_unlock(found); ao2_ref(found, -1); } return res; }
int ast_unreal_answer(struct ast_channel *ast) { struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast); int isoutbound; int res = -1; if (!p) { return -1; } ao2_ref(p, 1); ao2_lock(p); isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p); if (isoutbound) { /* Pass along answer since somebody answered us */ struct ast_frame answer = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } }; res = unreal_queue_frame(p, isoutbound, &answer, ast, 1); } else { ast_log(LOG_WARNING, "Huh? %s is being asked to answer?\n", ast_channel_name(ast)); } ao2_unlock(p); ao2_ref(p, -1); return res; }
/*! \brief Hangup a call through the local proxy channel */ static int local_hangup(struct ast_channel *ast) { struct local_pvt *p = ast_channel_tech_pvt(ast); int res; if (!p) { return -1; } /* give the pvt a ref to fulfill calling requirements. */ ao2_ref(p, +1); res = ast_unreal_hangup(&p->base, ast); if (!res) { int unlink; ao2_lock(p); unlink = !p->base.owner && !p->base.chan; ao2_unlock(p); if (unlink) { ao2_unlink(locals, p); } } ao2_ref(p, -1); return res; }
struct ast_channel *ast_local_get_peer(struct ast_channel *ast) { struct local_pvt *p = ast_channel_tech_pvt(ast); struct local_pvt *found; struct ast_channel *peer; if (!p) { return NULL; } found = p ? ao2_find(locals, p, 0) : NULL; if (!found) { /* ast is either not a local channel or it has alredy been hungup */ return NULL; } ao2_lock(found); if (ast == p->base.owner) { peer = p->base.chan; } else if (ast == p->base.chan) { peer = p->base.owner; } else { peer = NULL; } if (peer) { ast_channel_ref(peer); } ao2_unlock(found); ao2_ref(found, -1); return peer; }
/*! \brief Return the bridged channel of a Local channel */ static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge) { struct local_pvt *p = ast_channel_tech_pvt(bridge); struct ast_channel *bridged = bridge; if (!p) { ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n", ast_channel_name(chan), ast_channel_name(bridge)); return NULL; } ao2_lock(p); if (ast_test_flag(p, LOCAL_BRIDGE)) { /* Find the opposite channel */ bridged = (bridge == p->owner ? p->chan : p->owner); /* Now see if the opposite channel is bridged to anything */ if (!bridged) { bridged = bridge; } else if (ast_channel_internal_bridged_channel(bridged)) { bridged = ast_channel_internal_bridged_channel(bridged); } } ao2_unlock(p); return bridged; }
/* Called with ast locked */ static int local_setoption(struct ast_channel *ast, int option, void * data, int datalen) { int res = 0; struct local_pvt *p = NULL; struct ast_channel *otherchan = NULL; ast_chan_write_info_t *write_info; if (option != AST_OPTION_CHANNEL_WRITE) { return -1; } write_info = data; if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) { ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n"); return -1; } if (!strcmp(write_info->function, "CHANNEL") && !strncasecmp(write_info->data, "hangup_handler_", 15)) { /* Block CHANNEL(hangup_handler_xxx) writes to the other local channel. */ return 0; } /* get the tech pvt */ if (!(p = ast_channel_tech_pvt(ast))) { return -1; } ao2_ref(p, 1); ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */ /* get the channel we are supposed to write to */ ao2_lock(p); otherchan = (write_info->chan == p->owner) ? p->chan : p->owner; if (!otherchan || otherchan == write_info->chan) { res = -1; otherchan = NULL; ao2_unlock(p); goto setoption_cleanup; } ast_channel_ref(otherchan); /* clear the pvt lock before grabbing the channel */ ao2_unlock(p); ast_channel_lock(otherchan); res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value); ast_channel_unlock(otherchan); setoption_cleanup: if (p) { ao2_ref(p, -1); } if (otherchan) { ast_channel_unref(otherchan); } ast_channel_lock(ast); /* Lock back before we leave */ return res; }
/*! \brief Function called when we should actually call the destination */ static int multicast_rtp_call(struct ast_channel *ast, const char *dest, int timeout) { struct ast_rtp_instance *instance = ast_channel_tech_pvt(ast); ast_queue_control(ast, AST_CONTROL_ANSWER); return ast_rtp_instance_activate(instance); }
/*! * \brief handler for incoming calls. Either autoanswer, or start ringing */ static int oss_call(struct ast_channel *c, const char *dest, int timeout) { struct chan_oss_pvt *o = ast_channel_tech_pvt(c); struct ast_frame f = { AST_FRAME_CONTROL, }; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(name); AST_APP_ARG(flags); );
/*! * \brief Implements function 'read' callback. * * Valid actions are 'read' and 'remove'. */ static int func_read_header(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len) { struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL; struct header_data header_data; int number; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(action); AST_APP_ARG(header_name); AST_APP_ARG(header_number););
/*! * \internal \brief Handle reading RTP information */ static int channel_read_rtp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan); struct chan_pjsip_pvt *pvt; struct ast_sip_session_media *media = NULL; struct ast_sockaddr addr; if (!channel) { ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan)); return -1; } pvt = channel->pvt; if (!pvt) { ast_log(AST_LOG_WARNING, "Channel %s has no chan_pjsip pvt!\n", ast_channel_name(chan)); return -1; } if (ast_strlen_zero(type)) { ast_log(AST_LOG_WARNING, "You must supply a type field for 'rtp' information\n"); return -1; } if (ast_strlen_zero(field) || !strcmp(field, "audio")) { media = pvt->media[SIP_MEDIA_AUDIO]; } else if (!strcmp(field, "video")) { media = pvt->media[SIP_MEDIA_VIDEO]; } else { ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtp' information\n", field); return -1; } if (!media || !media->rtp) { ast_log(AST_LOG_WARNING, "Channel %s has no %s media/RTP session\n", ast_channel_name(chan), S_OR(field, "audio")); return -1; } if (!strcmp(type, "src")) { ast_rtp_instance_get_local_address(media->rtp, &addr); ast_copy_string(buf, ast_sockaddr_stringify(&addr), buflen); } else if (!strcmp(type, "dest")) { ast_rtp_instance_get_remote_address(media->rtp, &addr); ast_copy_string(buf, ast_sockaddr_stringify(&addr), buflen); } else if (!strcmp(type, "direct")) { ast_copy_string(buf, ast_sockaddr_stringify(&media->direct_media_addr), buflen); } else if (!strcmp(type, "secure")) { snprintf(buf, buflen, "%d", media->srtp ? 1 : 0); } else if (!strcmp(type, "hold")) { snprintf(buf, buflen, "%d", media->remotely_held ? 1 : 0); } else { ast_log(AST_LOG_WARNING, "Unknown type field '%s' specified for 'rtp' information\n", type); return -1; } return 0; }
/*! \brief Function called when we should hang the channel up */ static int multicast_rtp_hangup(struct ast_channel *ast) { struct ast_rtp_instance *instance = ast_channel_tech_pvt(ast); ast_rtp_instance_destroy(instance); ast_channel_tech_pvt_set(ast, NULL); return 0; }
int sip_acf_channel_read(struct ast_channel *chan, const char *funcname, char *preparse, char *buf, size_t buflen) { struct sip_pvt *p = ast_channel_tech_pvt(chan); char *parse = ast_strdupa(preparse); int res = 0; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(param); AST_APP_ARG(type); AST_APP_ARG(field); );
static int respoke_metadata_function_read(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len) { char *parsed_data = ast_strdupa(data); const char *key; const struct respoke_session *session = chan ? ast_channel_tech_pvt(chan) : NULL; struct ast_json *value_json; int res = -1; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(key); );
/*! \brief Frame hook callback for T.38 related stuff */ static struct ast_frame *t38_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan); if (event == AST_FRAMEHOOK_EVENT_READ) { f = t38_framehook_read(channel->session, f); } else if (event == AST_FRAMEHOOK_EVENT_WRITE) { f = t38_framehook_write(channel->session, f); } return f; }
static int snoop_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) { struct stasis_app_snoop *snoop = ast_channel_tech_pvt(oldchan); if (snoop->chan != oldchan) { return -1; } ast_channel_unref(snoop->chan); ast_channel_ref(newchan); snoop->chan = newchan; return 0; }
static int media_hangup(struct ast_channel *ast) { struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast); int res; if (!p) { return -1; } /* Give the pvt a ref to fulfill calling requirements. */ ao2_ref(p, +1); res = ast_unreal_hangup(p, ast); ao2_ref(p, -1); return res; }
/* Called with ast locked */ static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen) { struct local_pvt *p; struct ast_channel *bridged = NULL; struct ast_channel *tmp = NULL; int res = 0; if (option != AST_OPTION_T38_STATE) { /* AST_OPTION_T38_STATE is the only supported option at this time */ return -1; } /* for some reason the channel is not locked in channel.c when this function is called */ if (!(p = ast_channel_tech_pvt(ast))) { return -1; } ao2_lock(p); if (!(tmp = IS_OUTBOUND(ast, p) ? p->owner : p->chan)) { ao2_unlock(p); return -1; } ast_channel_ref(tmp); ao2_unlock(p); ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */ ast_channel_lock(tmp); if (!(bridged = ast_bridged_channel(tmp))) { res = -1; ast_channel_unlock(tmp); goto query_cleanup; } ast_channel_ref(bridged); ast_channel_unlock(tmp); query_cleanup: if (bridged) { res = ast_channel_queryoption(bridged, option, data, datalen, 0); bridged = ast_channel_unref(bridged); } if (tmp) { tmp = ast_channel_unref(tmp); } ast_channel_lock(ast); /* Lock back before we leave */ return res; }
int sccpconf_announce_channel_push(struct ast_channel *ast, struct ast_bridge *bridge) { struct ast_bridge_features *features; struct ast_channel *chan; struct announce_pvt *p = NULL; { ast_channel_lock(ast); p = ast_channel_tech_pvt(ast); if (!p) { ast_channel_unlock(ast); return -1; } ao2_ref(p, +1); chan = p->base.chan; if (!chan) { ast_channel_unlock(ast); ao2_cleanup(p); return -1; } ast_channel_ref(chan); ast_channel_unlock(ast); } features = ast_bridge_features_new(); if (!features) { ast_channel_unref(chan); ao2_cleanup(p); return -1; } ast_set_flag(&features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE); // Impart the output channel into the bridge if (ast_bridge_impart(bridge, chan, NULL, features, AST_BRIDGE_IMPART_CHAN_DEPARTABLE)) { ast_bridge_features_destroy(features); ast_channel_unref(chan); ao2_cleanup(p); return -1; } ao2_lock(p); ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD); ao2_unlock(p); ao2_cleanup(p); return 0; }
/*! \brief Callback function for writing to a Snoop whisper audiohook */ static int snoop_write(struct ast_channel *chan, struct ast_frame *frame) { struct stasis_app_snoop *snoop = ast_channel_tech_pvt(chan); if (!snoop->whisper_active) { return 0; } ast_audiohook_lock(&snoop->whisper); if (snoop->whisper_direction == AST_AUDIOHOOK_DIRECTION_BOTH) { ast_audiohook_write_frame(&snoop->whisper, AST_AUDIOHOOK_DIRECTION_READ, frame); ast_audiohook_write_frame(&snoop->whisper, AST_AUDIOHOOK_DIRECTION_WRITE, frame); } else { ast_audiohook_write_frame(&snoop->whisper, snoop->whisper_direction, frame); } ast_audiohook_unlock(&snoop->whisper); return 0; }
int ast_unreal_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) { struct ast_unreal_pvt *p = ast_channel_tech_pvt(newchan); struct ast_bridge *bridge_owner; struct ast_bridge *bridge_chan; if (!p) { return -1; } ao2_lock(p); if ((p->owner != oldchan) && (p->chan != oldchan)) { ast_log(LOG_WARNING, "Old channel %p wasn't %p or %p\n", oldchan, p->owner, p->chan); ao2_unlock(p); return -1; } if (p->owner == oldchan) { p->owner = newchan; } else { p->chan = newchan; } if (ast_check_hangup(newchan) || !p->owner || !p->chan) { ao2_unlock(p); return 0; } /* Do not let a masquerade cause an unreal channel to be bridged to itself! */ bridge_owner = ast_channel_internal_bridge(p->owner); bridge_chan = ast_channel_internal_bridge(p->chan); if (bridge_owner && bridge_owner == bridge_chan) { ast_log(LOG_WARNING, "You can not bridge an unreal channel (%s) to itself!\n", ast_channel_name(newchan)); ao2_unlock(p); ast_queue_hangup(newchan); return -1; } ao2_unlock(p); return 0; }
int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features) { struct local_pvt *p; struct local_pvt *found; int res = -1; /* Sanity checks. */ if (!ast || !bridge) { ast_bridge_features_destroy(features); return -1; } ast_channel_lock(ast); p = ast_channel_tech_pvt(ast); ast_channel_unlock(ast); found = p ? ao2_find(locals, p, 0) : NULL; if (found) { ao2_lock(found); if (found->type == LOCAL_CALL_ACTION_DIALPLAN && found->base.owner && found->base.chan && !ast_test_flag(&found->base, AST_UNREAL_CARETAKER_THREAD)) { ao2_ref(bridge, +1); if (swap) { ast_channel_ref(swap); } found->type = LOCAL_CALL_ACTION_BRIDGE; found->action.bridge.join = bridge; found->action.bridge.swap = swap; found->action.bridge.features = features; res = 0; } else { ast_bridge_features_destroy(features); } ao2_unlock(found); ao2_ref(found, -1); } return res; }
static int local_digit_begin(struct ast_channel *ast, char digit) { struct local_pvt *p = ast_channel_tech_pvt(ast); int res = -1; struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; int isoutbound; if (!p) { return -1; } ao2_ref(p, 1); /* ref for local_queue_frame */ ao2_lock(p); isoutbound = IS_OUTBOUND(ast, p); f.subclass.integer = digit; res = local_queue_frame(p, isoutbound, &f, ast, 0); ao2_unlock(p); ao2_ref(p, -1); return res; }
/*! \brief Callback function for reading from a Snoop channel */ static struct ast_frame *snoop_read(struct ast_channel *chan) { struct stasis_app_snoop *snoop = ast_channel_tech_pvt(chan); struct ast_frame *frame = NULL; /* If we fail to ack the timer OR if any active audiohooks are done hangup */ if ((ast_timer_ack(snoop->timer, 1) < 0) || (snoop->spy_active && snoop->spy.status != AST_AUDIOHOOK_STATUS_RUNNING) || (snoop->whisper_active && snoop->whisper.status != AST_AUDIOHOOK_STATUS_RUNNING)) { return NULL; } /* Only get audio from the spy audiohook if it is active */ if (snoop->spy_active) { ast_audiohook_lock(&snoop->spy); frame = ast_audiohook_read_frame(&snoop->spy, snoop->spy_samples, snoop->spy_direction, snoop->spy_format); ast_audiohook_unlock(&snoop->spy); } return frame ? frame : &ast_null_frame; }
static int local_sendtext(struct ast_channel *ast, const char *text) { struct local_pvt *p = ast_channel_tech_pvt(ast); int res = -1; struct ast_frame f = { AST_FRAME_TEXT, }; int isoutbound; if (!p) { return -1; } ao2_lock(p); ao2_ref(p, 1); /* ref for local_queue_frame */ isoutbound = IS_OUTBOUND(ast, p); f.data.ptr = (char *) text; f.datalen = strlen(text) + 1; res = local_queue_frame(p, isoutbound, &f, ast, 0); ao2_unlock(p); ao2_ref(p, -1); return res; }
static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen) { struct local_pvt *p = ast_channel_tech_pvt(ast); int res = -1; struct ast_frame f = { AST_FRAME_HTML, }; int isoutbound; if (!p) { return -1; } ao2_lock(p); ao2_ref(p, 1); /* ref for local_queue_frame */ isoutbound = IS_OUTBOUND(ast, p); f.subclass.integer = subclass; f.data.ptr = (char *)data; f.datalen = datalen; res = local_queue_frame(p, isoutbound, &f, ast, 0); ao2_unlock(p); ao2_ref(p, -1); return res; }
/* Called with ast locked */ int ast_unreal_queryoption(struct ast_channel *ast, int option, void *data, int *datalen) { struct ast_unreal_pvt *p; struct ast_channel *peer; struct ast_channel *other; int res = 0; if (option != AST_OPTION_T38_STATE) { /* AST_OPTION_T38_STATE is the only supported option at this time */ return -1; } /* for some reason the channel is not locked in channel.c when this function is called */ if (!(p = ast_channel_tech_pvt(ast))) { return -1; } ao2_lock(p); other = AST_UNREAL_IS_OUTBOUND(ast, p) ? p->owner : p->chan; if (!other) { ao2_unlock(p); return -1; } ast_channel_ref(other); ao2_unlock(p); ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */ peer = ast_channel_bridge_peer(other); if (peer) { res = ast_channel_queryoption(peer, option, data, datalen, 0); ast_channel_unref(peer); } ast_channel_unref(other); ast_channel_lock(ast); /* Lock back before we leave */ return res; }