static void set_config_flags(struct ast_channel *chan, struct ast_bridge_config *config) { ast_clear_flag(config, AST_FLAGS_ALL); if (ast_test_flag(&config->features_caller, AST_FEATURE_DTMF_MASK)) { ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); } if (ast_test_flag(&config->features_callee, AST_FEATURE_DTMF_MASK)) { ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); } if (!(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { RAII_VAR(struct ao2_container *, applicationmap, NULL, ao2_cleanup); ast_channel_lock(chan); applicationmap = ast_get_chan_applicationmap(chan); ast_channel_unlock(chan); if (!applicationmap) { return; } /* If an applicationmap exists for this channel at all, then the channel needs the DTMF flag set */ ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); } }
const char *comedia_string(struct ast_flags *flags) { if (ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA)) { return ast_test_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP) ? "Auto (Yes)" : "Auto (No)"; } return AST_CLI_YESNO(ast_test_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP)); }
static void page_state_callback(struct ast_dial *dial) { struct ast_channel *chan; struct page_options *options; if (ast_dial_state(dial) != AST_DIAL_RESULT_ANSWERED || !(chan = ast_dial_answered(dial)) || !(options = ast_dial_get_user_data(dial))) { return; } ast_func_write(chan, "CONFBRIDGE(bridge,template)", "default_bridge"); if (ast_test_flag(&options->flags, PAGE_RECORD)) { ast_func_write(chan, "CONFBRIDGE(bridge,record_conference)", "yes"); } ast_func_write(chan, "CONFBRIDGE(user,quiet)", "yes"); ast_func_write(chan, "CONFBRIDGE(user,end_marked)", "yes"); if (!ast_test_flag(&options->flags, PAGE_DUPLEX)) { ast_func_write(chan, "CONFBRIDGE(user,startmuted)", "yes"); } if (ast_test_flag(&options->flags, PAGE_ANNOUNCE) && !ast_strlen_zero(options->opts[OPT_ARG_ANNOUNCE])) { ast_func_write(chan, "CONFBRIDGE(user,announcement)", options->opts[OPT_ARG_ANNOUNCE]); } }
static int resetcdr_exec(struct ast_channel *chan, const char *data) { RAII_VAR(struct app_cdr_message_payload *, payload, ao2_alloc(sizeof(*payload), NULL), ao2_cleanup); char *args; struct ast_flags flags = { 0 }; if (!payload) { return -1; } if (!ast_strlen_zero(data)) { args = ast_strdupa(data); ast_app_parse_options(resetcdr_opts, &flags, NULL, args); } payload->channel_name = ast_channel_name(chan); payload->reset = 1; if (ast_test_flag(&flags, AST_CDR_FLAG_DISABLE_ALL)) { payload->reenable = 1; } if (ast_test_flag(&flags, AST_CDR_FLAG_KEEP_VARS)) { payload->keep_variables = 1; } return publish_app_cdr_message(chan, payload); }
const char *force_rport_string(struct ast_flags *flags) { if (ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) { return ast_test_flag(&flags[0], SIP_NAT_FORCE_RPORT) ? "Auto (Yes)" : "Auto (No)"; } return AST_CLI_YESNO(ast_test_flag(&flags[0], SIP_NAT_FORCE_RPORT)); }
const char *ast_sdp_srtp_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32) { int taglen = default_taglen_32 ? 32 : 80; if (!srtp) { return NULL; } /* Set encryption properties */ if (!srtp->crypto) { srtp->crypto = ast_sdp_crypto_alloc(); } if (dtls_enabled) { /* If DTLS-SRTP is enabled the key details will be pulled from TLS */ return NULL; } /* set the key length based on INVITE or settings */ if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_80)) { taglen = 80; } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_32)) { taglen = 32; } if (srtp->crypto && (ast_sdp_crypto_build_offer(srtp->crypto, taglen) >= 0)) { return srtp->crypto->a_crypto; } ast_log(LOG_WARNING, "No SRTP key management enabled\n"); return NULL; }
/*! * \internal * \brief Setup the caller user profile. * * \param chan Setup user profile on this channel. * \param options Options to setup caller user profile. * * \return Nothing */ static void setup_profile_caller(struct ast_channel *chan, struct page_options *options) { /* Use default_user as a starting point if not already setup. */ ast_func_write(chan, "CONFBRIDGE(user,template)", ""); ast_func_write(chan, "CONFBRIDGE(user,quiet)", "yes"); ast_func_write(chan, "CONFBRIDGE(user,marked)", "yes"); if (!ast_test_flag(&options->flags, PAGE_NOCALLERANNOUNCE) && ast_test_flag(&options->flags, PAGE_ANNOUNCE) && !ast_strlen_zero(options->opts[OPT_ARG_ANNOUNCE])) { ast_func_write(chan, "CONFBRIDGE(user,announcement)", options->opts[OPT_ARG_ANNOUNCE]); } }
/*! * \internal brief Setup limit hook structures on calls that need limits * * \param config ast_bridge_config which provides the limit data * \param caller_limits pointer to an ast_bridge_features_limits struct which will store the caller side limits * \param callee_limits pointer to an ast_bridge_features_limits struct which will store the callee side limits */ static void bridge_config_set_limits(struct ast_bridge_config *config, struct ast_bridge_features_limits *caller_limits, struct ast_bridge_features_limits *callee_limits) { if (ast_test_flag(&config->features_caller, AST_FEATURE_PLAY_WARNING)) { bridge_config_set_limits_warning_values(config, caller_limits); } if (ast_test_flag(&config->features_callee, AST_FEATURE_PLAY_WARNING)) { bridge_config_set_limits_warning_values(config, callee_limits); } caller_limits->duration = config->timelimit; callee_limits->duration = config->timelimit; }
static int app_exec(struct ast_channel *chan, void *data) { int res = 0; struct ast_flags flags; struct localuser *u; char *options=NULL; char *dummy = NULL; char *args; int argc = 0; char *opts[2]; char *argv[2]; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "%s requires an argument (dummy|[options])\n",app); return -1; } LOCAL_USER_ADD(u); /* Do our thing here */ /* We need to make a copy of the input string if we are going to modify it! */ args = ast_strdupa(data); if (!args) { ast_log(LOG_ERROR, "Out of memory!\n"); LOCAL_USER_REMOVE(u); return -1; } if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) { dummy = argv[0]; options = argv[1]; ast_app_parse_options(app_opts, &flags, opts, options); } if (!ast_strlen_zero(dummy)) ast_log(LOG_NOTICE, "Dummy value is : %s\n", dummy); if (ast_test_flag(&flags, OPTION_A)) ast_log(LOG_NOTICE, "Option A is set\n"); if (ast_test_flag(&flags, OPTION_B)) ast_log(LOG_NOTICE,"Option B is set with : %s\n", opts[0] ? opts[0] : "<unspecified>"); if (ast_test_flag(&flags, OPTION_C)) ast_log(LOG_NOTICE,"Option C is set with : %s\n", opts[1] ? opts[1] : "<unspecified>"); LOCAL_USER_REMOVE(u); return res; }
int ast_jb_do_usecheck(struct ast_channel *c0, struct ast_channel *c1) { struct ast_jb *jb0 = ast_channel_jb(c0); struct ast_jb *jb1 = ast_channel_jb(c1); struct ast_jb_conf *conf0 = &jb0->conf; struct ast_jb_conf *conf1 = &jb1->conf; int c0_wants_jitter = ast_channel_tech(c0)->properties & AST_CHAN_TP_WANTSJITTER; int c0_creates_jitter = ast_channel_tech(c0)->properties & AST_CHAN_TP_CREATESJITTER; int c0_jb_enabled = ast_test_flag(conf0, AST_JB_ENABLED); int c0_force_jb = ast_test_flag(conf0, AST_JB_FORCED); int c0_jb_timebase_initialized = ast_test_flag(jb0, JB_TIMEBASE_INITIALIZED); int c0_jb_created = ast_test_flag(jb0, JB_CREATED); int c1_wants_jitter = ast_channel_tech(c1)->properties & AST_CHAN_TP_WANTSJITTER; int c1_creates_jitter = ast_channel_tech(c1)->properties & AST_CHAN_TP_CREATESJITTER; int c1_jb_enabled = ast_test_flag(conf1, AST_JB_ENABLED); int c1_force_jb = ast_test_flag(conf1, AST_JB_FORCED); int c1_jb_timebase_initialized = ast_test_flag(jb1, JB_TIMEBASE_INITIALIZED); int c1_jb_created = ast_test_flag(jb1, JB_CREATED); int inuse = 0; /* Determine whether audio going to c0 needs a jitter buffer */ if (((!c0_wants_jitter && c1_creates_jitter) || (c0_force_jb && c1_creates_jitter)) && c0_jb_enabled) { ast_set_flag(jb0, JB_USE); if (!c0_jb_timebase_initialized) { if (c1_jb_timebase_initialized) { memcpy(&jb0->timebase, &jb1->timebase, sizeof(struct timeval)); } else { gettimeofday(&jb0->timebase, NULL); } ast_set_flag(jb0, JB_TIMEBASE_INITIALIZED); } if (!c0_jb_created) { jb_choose_impl(c0); } inuse = 1; } /* Determine whether audio going to c1 needs a jitter buffer */ if (((!c1_wants_jitter && c0_creates_jitter) || (c1_force_jb && c0_creates_jitter)) && c1_jb_enabled) { ast_set_flag(jb1, JB_USE); if (!c1_jb_timebase_initialized) { if (c0_jb_timebase_initialized) { memcpy(&jb1->timebase, &jb0->timebase, sizeof(struct timeval)); } else { gettimeofday(&jb1->timebase, NULL); } ast_set_flag(jb1, JB_TIMEBASE_INITIALIZED); } if (!c1_jb_created) { jb_choose_impl(c1); } inuse = 1; } return inuse; }
/*! * \internal * \brief Setup the paged user profile. * * \param chan Setup user profile on this channel. * \param options Options to setup paged user profile. * * \return Nothing */ static void setup_profile_paged(struct ast_channel *chan, struct page_options *options) { /* Use default_user as a starting point */ ast_func_write(chan, "CONFBRIDGE(user,template)", ""); ast_func_write(chan, "CONFBRIDGE(user,quiet)", "yes"); ast_func_write(chan, "CONFBRIDGE(user,end_marked)", "yes"); if (!ast_test_flag(&options->flags, PAGE_DUPLEX)) { ast_func_write(chan, "CONFBRIDGE(user,startmuted)", "yes"); } if (ast_test_flag(&options->flags, PAGE_ANNOUNCE) && !ast_strlen_zero(options->opts[OPT_ARG_ANNOUNCE])) { ast_func_write(chan, "CONFBRIDGE(user,announcement)", options->opts[OPT_ARG_ANNOUNCE]); } }
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags) { ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, ast_channel_name(autochan->chan)); if(ast_test_flag(flags, OPTION_READONLY)) { ast_set_flag(audiohook, AST_AUDIOHOOK_MUTE_WRITE); } else { ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC); } if(ast_test_flag(flags, OPTION_LONG_QUEUE)) { ast_debug(9, "Using a long queue to store audio frames in spy audiohook\n"); } else { ast_set_flag(audiohook, AST_AUDIOHOOK_SMALL_QUEUE); } return ast_audiohook_attach(autochan->chan, audiohook); }
void ast_jb_get_and_deliver(struct ast_channel *c0, struct ast_channel *c1) { struct ast_jb *jb0 = ast_channel_jb(c0); struct ast_jb *jb1 = ast_channel_jb(c1); int c0_use_jb = ast_test_flag(jb0, JB_USE); int c0_jb_is_created = ast_test_flag(jb0, JB_CREATED); int c1_use_jb = ast_test_flag(jb1, JB_USE); int c1_jb_is_created = ast_test_flag(jb1, JB_CREATED); if (c0_use_jb && c0_jb_is_created) jb_get_and_deliver(c0); if (c1_use_jb && c1_jb_is_created) jb_get_and_deliver(c1); }
/*! * \brief Remove a call file from the outgoing queue optionally moving it in the archive dir * * \param o the pointer to outgoing struct * \param status the exit status of the call. Can be "Completed", "Failed" or "Expired" */ static int remove_from_queue(struct outgoing *o, const char *status) { int fd; FILE *f; char newfn[256]; const char *bname; if (!ast_test_flag(&o->options, SPOOL_FLAG_ALWAYS_DELETE)) { struct stat current_file_status; if (!stat(o->fn, ¤t_file_status)) if (time(NULL) < current_file_status.st_mtime) return 0; } if (!ast_test_flag(&o->options, SPOOL_FLAG_ARCHIVE)) { unlink(o->fn); return 0; } if (mkdir(qdonedir, 0700) && (errno != EEXIST)) { ast_log(LOG_WARNING, "Unable to create queue directory %s -- outgoing spool archiving disabled\n", qdonedir); unlink(o->fn); return -1; } fd = open(o->fn, O_WRONLY|O_APPEND); if (fd > -1) { f = fdopen(fd, "a"); if (f) { fprintf(f, "Status: %s\n", status); fclose(f); } else close(fd); } bname = strrchr(o->fn,'/'); if (bname == NULL) bname = o->fn; else bname++; snprintf(newfn, sizeof(newfn), "%s/%s", qdonedir, bname); /* a existing call file the archive dir is overwritten */ unlink(newfn); if (rename(o->fn, newfn) != 0) { unlink(o->fn); return -1; } else 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; }
static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag) { /* Initialize the file if not already done so */ char *ext = NULL; char *last_slash = NULL; if (!ast_strlen_zero(filename)) { if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) { *oflags = O_CREAT | O_WRONLY; *oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC; last_slash = strrchr(filename, '/'); if ((ext = strrchr(filename, '.')) && (ext > last_slash)) { *(ext++) = '\0'; } else { ext = "raw"; } if (!(*fs = ast_writefile(filename, ext, NULL, *oflags, 0, 0666))) { ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, ext); *errflag = 1; } else { struct ast_filestream *tmp = *fs; mixmonitor->mixmonitor_ds->samp_rate = MAX(mixmonitor->mixmonitor_ds->samp_rate, ast_format_rate(&tmp->fmt->format)); } } } }
/*! \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; }
int ast_autoservice_stop(struct ast_channel *chan) { int res = -1; struct asent *as, *prev; ast_mutex_lock(&autolock); as = aslist; prev = NULL; while(as) { if (as->chan == chan) break; prev = as; as = as->next; } if (as) { if (prev) prev->next = as->next; else aslist = as->next; free(as); if (!chan->_softhangup) res = 0; } if (asthread != AST_PTHREADT_NULL) pthread_kill(asthread, SIGURG); ast_mutex_unlock(&autolock); /* Wait for it to un-block */ while(ast_test_flag(chan, AST_FLAG_BLOCKING)) usleep(1000); return res; }
void ast_jb_destroy(struct ast_channel *chan) { struct ast_jb *jb = ast_channel_jb(chan); const struct ast_jb_impl *jbimpl = jb->impl; void *jbobj = jb->jbobj; struct ast_frame *f; if (jb->logfile) { fclose(jb->logfile); jb->logfile = NULL; } if (ast_test_flag(jb, JB_CREATED)) { /* Remove and free all frames still queued in jb */ while (jbimpl->remove(jbobj, &f) == AST_JB_IMPL_OK) { ast_frfree(f); } jbimpl->destroy(jbobj); jb->jbobj = NULL; ast_clear_flag(jb, JB_CREATED); ast_verb(3, "%s jitterbuffer destroyed on channel %s\n", jbimpl->name, ast_channel_name(chan)); } }
static int load_module(void) { CHECK_PJSIP_MODULE_LOADED(); if (ast_sip_register_subscription_handler(&mwi_handler)) { return AST_MODULE_LOAD_DECLINE; } unsolicited_mwi = ao2_container_alloc(MWI_BUCKETS, mwi_sub_hash, mwi_sub_cmp); if (!unsolicited_mwi) { ast_sip_unregister_subscription_handler(&mwi_handler); return AST_MODULE_LOAD_DECLINE; } create_mwi_subscriptions(); ast_sorcery_observer_add(ast_sip_get_sorcery(), "contact", &mwi_contact_observer); if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) { ast_sip_push_task(NULL, send_initial_notify_all, NULL); } else { stasis_subscribe_pool(ast_manager_get_topic(), mwi_startup_event_cb, NULL); } return AST_MODULE_LOAD_SUCCESS; }
void ast_jb_enable_for_channel(struct ast_channel *chan) { struct ast_jb_conf conf = ast_channel_jb(chan)->conf; if (ast_test_flag(&conf, AST_JB_ENABLED)) { ast_jb_create_framehook(chan, &conf, 1); } }
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; }
/*! * \internal * \brief Used to determine what action to take when DTMF is received while recording * \since 13.0.0 * * \param chan channel being recorded * \param flags option flags in use by the record application * \param dtmf_integer the integer value of the DTMF key received * \param terminator key currently set to be pressed for normal termination * * \retval 0 do not exit * \retval -1 do exit */ static int record_dtmf_response(struct ast_channel *chan, struct ast_flags *flags, int dtmf_integer, int terminator) { if ((dtmf_integer == OPERATOR_KEY) && (ast_test_flag(flags, OPTION_OPERATOR_EXIT))) { pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "OPERATOR"); return -1; } if ((dtmf_integer == terminator) || (ast_test_flag(flags, OPTION_ANY_TERMINATE))) { pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "DTMF"); return -1; } return 0; }
static void ast_cdr_fork(struct ast_channel *chan, struct ast_flags optflags, char *set) { struct ast_cdr *cdr; struct ast_cdr *newcdr; struct ast_flags flags = { AST_CDR_FLAG_KEEP_VARS }; cdr = ast_channel_cdr(chan); while (cdr->next) cdr = cdr->next; if (!(newcdr = ast_cdr_dup_unique(cdr))) return; /* * End the original CDR if requested BEFORE appending the new CDR * otherwise we incorrectly end the new CDR also. */ if (ast_test_flag(&optflags, OPT_ENDCDR)) { ast_cdr_end(cdr); } ast_cdr_append(cdr, newcdr); if (!ast_test_flag(&optflags, OPT_NORESET)) ast_cdr_reset(newcdr, &flags); if (!ast_test_flag(cdr, AST_CDR_FLAG_KEEP_VARS)) ast_cdr_free_vars(cdr, 0); if (!ast_strlen_zero(set)) { char *varname = ast_strdupa(set), *varval; varval = strchr(varname,'='); if (varval) { *varval = 0; varval++; ast_cdr_setvar(cdr, varname, varval, 0); } } if (ast_test_flag(&optflags, OPT_SETANS) && !ast_tvzero(cdr->answer)) newcdr->answer = newcdr->start; if (ast_test_flag(&optflags, OPT_SETDISP)) newcdr->disposition = cdr->disposition; if (ast_test_flag(&optflags, OPT_RESETDEST)) newcdr->dstchannel[0] = 0; if (ast_test_flag(&optflags, OPT_ANSLOCK)) ast_set_flag(cdr, AST_CDR_FLAG_ANSLOCKED); if (ast_test_flag(&optflags, OPT_DONTOUCH)) ast_set_flag(cdr, AST_CDR_FLAG_DONT_TOUCH); ast_set_flag(cdr, AST_CDR_FLAG_CHILD | AST_CDR_FLAG_LOCKED); }
void ast_jb_empty_and_reset(struct ast_channel *c0, struct ast_channel *c1) { struct ast_jb *jb0 = ast_channel_jb(c0); struct ast_jb *jb1 = ast_channel_jb(c1); int c0_use_jb = ast_test_flag(jb0, JB_USE); int c0_jb_is_created = ast_test_flag(jb0, JB_CREATED); int c1_use_jb = ast_test_flag(jb1, JB_USE); int c1_jb_is_created = ast_test_flag(jb1, JB_CREATED); if (c0_use_jb && c0_jb_is_created && jb0->impl->empty_and_reset) { jb0->impl->empty_and_reset(jb0->jbobj); } if (c1_use_jb && c1_jb_is_created && jb1->impl->empty_and_reset) { jb1->impl->empty_and_reset(jb1->jbobj); } }
/*! * \internal * \brief Setup the page bridge profile. * * \param chan Setup bridge profile on this channel. * \param options Options to setup bridge profile. * * \return Nothing */ static void setup_profile_bridge(struct ast_channel *chan, struct page_options *options) { /* Use default_bridge as a starting point */ ast_func_write(chan, "CONFBRIDGE(bridge,template)", ""); if (ast_test_flag(&options->flags, PAGE_RECORD)) { ast_func_write(chan, "CONFBRIDGE(bridge,record_conference)", "yes"); } }
/*! * \internal * \brief Post the \ref ast_local_bridge_type \ref stasis message * \since 12.0.0 * * \param p local_pvt to raise the local bridge message * * \return Nothing */ static void publish_local_bridge_message(struct local_pvt *p) { RAII_VAR(struct ast_multi_channel_blob *, multi_blob, NULL, ao2_cleanup); RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); RAII_VAR(struct ast_channel_snapshot *, one_snapshot, NULL, ao2_cleanup); RAII_VAR(struct ast_channel_snapshot *, two_snapshot, NULL, ao2_cleanup); struct ast_channel *owner; struct ast_channel *chan; if (!ast_local_bridge_type()) { return; } ast_unreal_lock_all(&p->base, &chan, &owner); blob = ast_json_pack("{s: s, s: s, s: b}", "context", p->context, "exten", p->exten, "can_optimize", !ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION)); if (!blob) { goto end; } multi_blob = ast_multi_channel_blob_create(blob); if (!multi_blob) { goto end; } one_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(owner)); if (!one_snapshot) { goto end; } two_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan)); if (!two_snapshot) { goto end; } ast_multi_channel_blob_add_channel(multi_blob, "1", one_snapshot); ast_multi_channel_blob_add_channel(multi_blob, "2", two_snapshot); msg = stasis_message_create(ast_local_bridge_type(), multi_blob); if (!msg) { goto end; } stasis_publish(ast_channel_topic(owner), msg); end: ast_channel_unlock(owner); ast_channel_unref(owner); ast_channel_unlock(chan); ast_channel_unref(chan); ao2_unlock(&p->base); }
/*! * \internal * \brief Push this channel into the Stasis bridge. * \since 12.5.0 * * \param self Bridge to operate upon. * \param bridge_channel Bridge channel to push. * \param swap Bridge channel to swap places with if not NULL. * * \note On entry, self is already locked. * * \retval 0 on success. * \retval -1 on failure. The channel did not get pushed. */ static int bridge_stasis_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap) { struct stasis_app_control *control = stasis_app_control_find_by_channel(bridge_channel->chan); if (!control && !stasis_app_channel_is_internal(bridge_channel->chan)) { /* channel not in Stasis(), get it there */ ast_debug(1, "Bridge %s: pushing non-stasis %p(%s) setup to come back in under stasis\n", self->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan)); /* Attach after-bridge callback and pass ownership of swap_app to it */ if (ast_bridge_set_after_callback(bridge_channel->chan, bridge_stasis_run_cb, NULL, NULL)) { ast_log(LOG_ERROR, "Failed to set after bridge callback for bridge %s non-stasis push of %s\n", self->uniqueid, ast_channel_name(bridge_channel->chan)); return -1; } bridge_stasis_queue_join_action(self, bridge_channel, swap); /* Return -1 so the push fails and the after-bridge callback gets called * This keeps the bridging framework from putting the channel into the bridge * until the Stasis thread gets started, and then the channel is put into the bridge. */ return -1; } /* * If going into a holding bridge, default the role to participant, if * it has no compatible role currently */ if ((self->technology->capabilities & AST_BRIDGE_CAPABILITY_HOLDING) && !ast_channel_has_role(bridge_channel->chan, "announcer") && !ast_channel_has_role(bridge_channel->chan, "holding_participant")) { if (ast_channel_add_bridge_role(bridge_channel->chan, "holding_participant")) { ast_log(LOG_ERROR, "Failed to set holding participant on %s\n", ast_channel_name(bridge_channel->chan)); return -1; } if (ast_channel_set_bridge_role_option(bridge_channel->chan, "holding_participant", "idle_mode", "none")) { ast_log(LOG_ERROR, "Failed to set holding participant mode on %s\n", ast_channel_name(bridge_channel->chan)); return -1; } } ao2_cleanup(control); if (self->allowed_capabilities & STASIS_BRIDGE_MIXING_CAPABILITIES) { ast_bridge_channel_update_linkedids(bridge_channel, swap); if (ast_test_flag(&self->feature_flags, AST_BRIDGE_FLAG_SMART)) { ast_bridge_channel_update_accountcodes(bridge_channel, swap); } } return ast_bridge_base_v_table.push(self, bridge_channel, swap); }
static void ast_cdr_fork(struct ast_channel *chan, struct ast_flags optflags, char *set) { struct ast_cdr *cdr; struct ast_cdr *newcdr; struct ast_flags flags = { AST_CDR_FLAG_KEEP_VARS }; cdr = chan->cdr; while (cdr->next) cdr = cdr->next; if (!(newcdr = ast_cdr_dup(cdr))) return; ast_cdr_append(cdr, newcdr); if (!ast_test_flag(&optflags, OPT_NORESET)) ast_cdr_reset(newcdr, &flags); if (!ast_test_flag(cdr, AST_CDR_FLAG_KEEP_VARS)) ast_cdr_free_vars(cdr, 0); if (!ast_strlen_zero(set)) { char *varname = ast_strdupa(set), *varval; varval = strchr(varname,'='); if (varval) { *varval = 0; varval++; ast_cdr_setvar(cdr, varname, varval, 0); } } if (ast_test_flag(&optflags, OPT_SETANS) && !ast_tvzero(cdr->answer)) newcdr->answer = newcdr->start; if (ast_test_flag(&optflags, OPT_SETDISP)) newcdr->disposition = cdr->disposition; if (ast_test_flag(&optflags, OPT_RESETDEST)) newcdr->dstchannel[0] = 0; if (ast_test_flag(&optflags, OPT_ENDCDR)) ast_cdr_end(cdr); if (ast_test_flag(&optflags, OPT_ANSLOCK)) ast_set_flag(cdr, AST_CDR_FLAG_ANSLOCKED); if (ast_test_flag(&optflags, OPT_DONTOUCH)) ast_set_flag(cdr, AST_CDR_FLAG_DONT_TOUCH); ast_set_flag(cdr, AST_CDR_FLAG_CHILD | AST_CDR_FLAG_LOCKED); }
/*! \brief Create a call structure */ static struct local_pvt *local_alloc(const char *data, struct ast_format_cap *cap) { struct local_pvt *pvt; char *parse; char *context; char *opts; pvt = (struct local_pvt *) ast_unreal_alloc(sizeof(*pvt), local_pvt_destructor, cap); if (!pvt) { return NULL; } pvt->base.callbacks = &local_unreal_callbacks; parse = ast_strdupa(data); /* * Local channels intercept MOH by default. * * This is a silly default because it represents state held by * the local channels. Unless local channel optimization is * disabled, the state will dissapear when the local channels * optimize out. */ ast_set_flag(&pvt->base, AST_UNREAL_MOH_INTERCEPT); /* Look for options */ if ((opts = strchr(parse, '/'))) { *opts++ = '\0'; if (strchr(opts, 'n')) { ast_set_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION); } if (strchr(opts, 'j')) { if (ast_test_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION)) { ast_set_flag(&pvt->base.jb_conf, AST_JB_ENABLED); } else { ast_log(LOG_ERROR, "You must use the 'n' option with the 'j' option to enable the jitter buffer\n"); } } if (strchr(opts, 'm')) { ast_clear_flag(&pvt->base, AST_UNREAL_MOH_INTERCEPT); } } /* Look for a context */ if ((context = strchr(parse, '@'))) { *context++ = '\0'; } ast_copy_string(pvt->context, S_OR(context, "default"), sizeof(pvt->context)); ast_copy_string(pvt->exten, parse, sizeof(pvt->exten)); snprintf(pvt->base.name, sizeof(pvt->base.name), "%s@%s", pvt->exten, pvt->context); return pvt; /* this is returned with a ref */ }