static int create_parked_subscription_full(struct ast_channel *chan, const char *parkee_uuid, int hangup_after, struct transfer_channel_data *parked_channel_data) { struct ast_datastore *datastore; struct parked_subscription_datastore *parked_datastore; struct parked_subscription_data *subscription_data; char *parker_uuid = ast_strdupa(ast_channel_uniqueid(chan)); size_t parker_uuid_size = strlen(parker_uuid) + 1; /* If there is already a subscription, get rid of it. */ wipe_subscription_datastore(chan); if (!(datastore = ast_datastore_alloc(&parked_subscription_info, NULL))) { return -1; } if (!(parked_datastore = ast_calloc(1, sizeof(*parked_datastore)))) { ast_datastore_free(datastore); return -1; } if (!(subscription_data = ast_calloc(1, sizeof(*subscription_data) + parker_uuid_size + strlen(parkee_uuid) + 1))) { ast_datastore_free(datastore); ast_free(parked_datastore); return -1; } if (parked_channel_data) { subscription_data->transfer_data = parked_channel_data; ao2_ref(parked_channel_data, +1); } subscription_data->hangup_after = hangup_after; subscription_data->parkee_uuid = subscription_data->parker_uuid + parker_uuid_size; strcpy(subscription_data->parkee_uuid, parkee_uuid); strcpy(subscription_data->parker_uuid, parker_uuid); if (!(parked_datastore->parked_subscription = stasis_subscribe_pool(ast_parking_topic(), parker_update_cb, subscription_data))) { return -1; } datastore->data = parked_datastore; ast_channel_lock(chan); ast_channel_datastore_add(chan, datastore); ast_channel_unlock(chan); return 0; }
/*! \internal \brief Enable talk detection on the channel */ static int set_talk_detect(struct ast_channel *chan, int dsp_silence_threshold, int dsp_talking_threshold) { struct ast_datastore *datastore = NULL; struct talk_detect_params *td_params; SCOPED_CHANNELLOCK(chan_lock, chan); datastore = ast_channel_datastore_find(chan, &talk_detect_datastore, NULL); if (!datastore) { datastore = ast_datastore_alloc(&talk_detect_datastore, NULL); if (!datastore) { return -1; } td_params = ast_calloc(1, sizeof(*td_params)); if (!td_params) { ast_datastore_free(datastore); return -1; } ast_audiohook_init(&td_params->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "TALK_DETECT", AST_AUDIOHOOK_MANIPULATE_ALL_RATES); td_params->audiohook.manipulate_callback = talk_detect_audiohook_cb; ast_set_flag(&td_params->audiohook, AST_AUDIOHOOK_TRIGGER_READ); td_params->dsp = ast_dsp_new_with_rate(ast_format_get_sample_rate(ast_channel_rawreadformat(chan))); if (!td_params->dsp) { ast_datastore_free(datastore); ast_free(td_params); return -1; } datastore->data = td_params; ast_channel_datastore_add(chan, datastore); ast_audiohook_attach(chan, &td_params->audiohook); } else { /* Talk detection already enabled; update existing settings */ td_params = datastore->data; } td_params->dsp_talking_threshold = dsp_talking_threshold; td_params->dsp_silence_threshold = dsp_silence_threshold; ast_dsp_set_threshold(td_params->dsp, td_params->dsp_talking_threshold); return 0; }
/*! * \brief Dial timeout * * This is a bridge interval hook callback. The interval hook triggering * means that the dial timeout has been reached. If the channel has not * been answered by the time this callback is called, then the channel * is hung up * * \param bridge_channel Bridge channel on which interval hook has been called * \param ignore Ignored * \return -1 (i.e. remove the interval hook) */ static int bridge_timeout(struct ast_bridge_channel *bridge_channel, void *ignore) { struct ast_datastore *datastore; RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup); control = stasis_app_control_find_by_channel(bridge_channel->chan); ast_channel_lock(bridge_channel->chan); if (ast_channel_state(bridge_channel->chan) != AST_STATE_UP) { /* Don't bother removing the datastore because it will happen when the channel is hung up */ ast_channel_unlock(bridge_channel->chan); stasis_app_send_command_async(control, hangup_channel, NULL, NULL); return -1; } datastore = ast_channel_datastore_find(bridge_channel->chan, &timeout_datastore, NULL); if (!datastore) { ast_channel_unlock(bridge_channel->chan); return -1; } ast_channel_datastore_remove(bridge_channel->chan, datastore); ast_channel_unlock(bridge_channel->chan); ast_datastore_free(datastore); return -1; }
static int srv_query_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { struct ast_datastore *datastore; if (!chan) { ast_log(LOG_WARNING, "%s cannot be used without a channel\n", cmd); return -1; } if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "%s requires a service as an argument\n", cmd); return -1; } /* If they already called SRVQUERY for this service once, * we need to kill the old datastore. */ ast_channel_lock(chan); datastore = ast_channel_datastore_find(chan, &srv_result_datastore_info, data); ast_channel_unlock(chan); if (datastore) { ast_channel_datastore_remove(chan, datastore); ast_datastore_free(datastore); } if (!srv_datastore_setup(data, chan)) { return -1; } ast_copy_string(buf, data, len); return 0; }
/*! * \internal * \brief Set the features datastore if it doesn't exist. * * \param chan Channel to add features datastore * \param my_features The channel's feature flags * \param peer_features The channel's bridge peer feature flags * * \retval TRUE if features datastore already existed. */ static int add_features_datastore(struct ast_channel *chan, const struct ast_flags *my_features, const struct ast_flags *peer_features) { struct ast_datastore *datastore; struct ast_dial_features *dialfeatures; ast_channel_lock(chan); datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL); ast_channel_unlock(chan); if (datastore) { /* Already exists. */ return 1; } /* Create a new datastore with specified feature flags. */ datastore = ast_datastore_alloc(&dial_features_info, NULL); if (!datastore) { ast_log(LOG_WARNING, "Unable to create channel features datastore.\n"); return 0; } dialfeatures = ast_calloc(1, sizeof(*dialfeatures)); if (!dialfeatures) { ast_log(LOG_WARNING, "Unable to allocate memory for feature flags.\n"); ast_datastore_free(datastore); return 0; } ast_copy_flags(&dialfeatures->my_features, my_features, AST_FLAGS_ALL); ast_copy_flags(&dialfeatures->peer_features, peer_features, AST_FLAGS_ALL); datastore->inheritance = DATASTORE_INHERIT_FOREVER; datastore->data = dialfeatures; ast_channel_lock(chan); ast_channel_datastore_add(chan, datastore); ast_channel_unlock(chan); return 0; }
/*! \internal \brief Disable talk detection on the channel */ static int remove_talk_detect(struct ast_channel *chan) { struct ast_datastore *datastore = NULL; struct talk_detect_params *td_params; SCOPED_CHANNELLOCK(chan_lock, chan); datastore = ast_channel_datastore_find(chan, &talk_detect_datastore, NULL); if (!datastore) { ast_log(AST_LOG_WARNING, "Cannot remove TALK_DETECT from %s: TALK_DETECT not currently enabled\n", ast_channel_name(chan)); return -1; } td_params = datastore->data; if (ast_audiohook_remove(chan, &td_params->audiohook)) { ast_log(AST_LOG_WARNING, "Failed to remove TALK_DETECT audiohook from channel %s\n", ast_channel_name(chan)); return -1; } if (ast_channel_datastore_remove(chan, datastore)) { ast_log(AST_LOG_WARNING, "Failed to remove TALK_DETECT datastore from channel %s\n", ast_channel_name(chan)); return -1; } ast_datastore_free(datastore); return 0; }
static int frame_trace_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value) { struct frame_trace_data *framedata; struct ast_datastore *datastore = NULL; struct ast_framehook_interface interface = { .version = AST_FRAMEHOOK_INTERFACE_VERSION, .event_cb = hook_event_cb, .destroy_cb = hook_destroy_cb, }; int i = 0; if (!(framedata = ast_calloc(1, sizeof(*framedata)))) { return 0; } interface.data = framedata; if (!strcasecmp(data, "black")) { framedata->list_type = 1; } for (i = 0; i < ARRAY_LEN(frametype2str); i++) { if (strcasestr(value, frametype2str[i].str)) { framedata->values[i] = 1; } } ast_channel_lock(chan); i = ast_framehook_attach(chan, &interface); if (i >= 0) { int *id; if ((datastore = ast_channel_datastore_find(chan, &frame_trace_datastore, NULL))) { id = datastore->data; ast_framehook_detach(chan, *id); ast_channel_datastore_remove(chan, datastore); } if (!(datastore = ast_datastore_alloc(&frame_trace_datastore, NULL))) { ast_framehook_detach(chan, i); ast_channel_unlock(chan); return 0; } if (!(id = ast_calloc(1, sizeof(int)))) { ast_datastore_free(datastore); ast_framehook_detach(chan, i); ast_channel_unlock(chan); return 0; } *id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */ datastore->data = id; ast_channel_datastore_add(chan, datastore); } ast_channel_unlock(chan); return 0; }
static void wipe_subscription_datastore(struct ast_channel *chan) { struct ast_datastore *datastore; ast_channel_lock(chan); datastore = ast_channel_datastore_find(chan, &parked_subscription_info, NULL); if (datastore) { ast_channel_datastore_remove(chan, datastore); ast_datastore_free(datastore); } ast_channel_unlock(chan); }
/*! \brief Mute dialplan function */ static int func_mute_write(struct ast_channel *chan, const char *cmd, char *data, const char *value) { struct ast_datastore *datastore = NULL; struct mute_information *mute = NULL; int is_new = 0; if (!chan) { ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd); return -1; } ast_channel_lock(chan); if (!(datastore = ast_channel_datastore_find(chan, &mute_datastore, NULL))) { if (!(datastore = initialize_mutehook(chan))) { ast_channel_unlock(chan); return 0; } is_new = 1; } mute = datastore->data; if (!strcasecmp(data, "out")) { mute->mute_write = ast_true(value); ast_debug(1, "%s channel - outbound \n", ast_true(value) ? "Muting" : "Unmuting"); } else if (!strcasecmp(data, "in")) { mute->mute_read = ast_true(value); ast_debug(1, "%s channel - inbound \n", ast_true(value) ? "Muting" : "Unmuting"); } else if (!strcasecmp(data,"all")) { mute->mute_write = mute->mute_read = ast_true(value); } if (is_new) { if (mute_add_audiohook(chan, mute, datastore)) { /* Can't add audiohook - already printed error message */ ast_datastore_free(datastore); ast_free(mute); } } ast_channel_unlock(chan); return 0; }
/*! * \internal * \brief Destroy the speech datastore on the given channel. * * \param chan Channel to destroy speech datastore. * * \retval 0 on success. * \retval -1 not found. */ static int speech_datastore_destroy(struct ast_channel *chan) { struct ast_datastore *datastore; int res; ast_channel_lock(chan); datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL); if (datastore) { ast_channel_datastore_remove(chan, datastore); } ast_channel_unlock(chan); if (datastore) { ast_datastore_free(datastore); res = 0; } else { res = -1; } return res; }
/*! \brief Initialize mute hook on channel, but don't activate it \pre Assumes that the channel is locked */ static struct ast_datastore *initialize_mutehook(struct ast_channel *chan) { struct ast_datastore *datastore = NULL; struct mute_information *mute = NULL; ast_debug(2, "Initializing new Mute Audiohook \n"); /* Allocate a new datastore to hold the reference to this mute_datastore and audiohook information */ if (!(datastore = ast_datastore_alloc(&mute_datastore, NULL))) { return NULL; } if (!(mute = ast_calloc(1, sizeof(*mute)))) { ast_datastore_free(datastore); return NULL; } ast_audiohook_init(&mute->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Mute", AST_AUDIOHOOK_MANIPULATE_ALL_RATES); mute->audiohook.manipulate_callback = mute_callback; datastore->data = mute; return datastore; }
static int volume_write(struct ast_channel *chan, const char *cmd, char *data, const char *value) { struct ast_datastore *datastore = NULL; struct volume_information *vi = NULL; int is_new = 0; if (!(datastore = ast_channel_datastore_find(chan, &volume_datastore, NULL))) { /* Allocate a new datastore to hold the reference to this volume and audiohook information */ if (!(datastore = ast_datastore_alloc(&volume_datastore, NULL))) return 0; if (!(vi = ast_calloc(1, sizeof(*vi)))) { ast_datastore_free(datastore); return 0; } ast_audiohook_init(&vi->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume"); vi->audiohook.manipulate_callback = volume_callback; ast_set_flag(&vi->audiohook, AST_AUDIOHOOK_WANTS_DTMF); is_new = 1; } else { vi = datastore->data; } /* Adjust gain on volume information structure */ if (!strcasecmp(data, "tx")) vi->tx_gain = atoi(value); else if (!strcasecmp(data, "rx")) vi->rx_gain = atoi(value); if (is_new) { datastore->data = vi; ast_channel_datastore_add(chan, datastore); ast_audiohook_attach(chan, &vi->audiohook); } return 0; }
static void *hook_launch_thread(void *data) { struct hook_thread_arg *arg = data; struct ast_variable hook_id = { .name = "HOOK_ID", .value = arg->hook_id, }; struct ast_variable chan_name_var = { .name = "HOOK_CHANNEL", .value = arg->chan_name, .next = &hook_id, }; ast_pbx_outgoing_exten("Local", NULL, full_exten_name, 60, arg->context, arg->exten, 1, NULL, AST_OUTGOING_NO_WAIT, NULL, NULL, &chan_name_var, NULL, NULL, 1, NULL); hook_thread_arg_destroy(arg); return NULL; } static struct hook_thread_arg *hook_thread_arg_alloc(struct ast_channel *chan, struct hook_state *state) { struct hook_thread_arg *arg; if (!(arg = ast_calloc(1, sizeof(*arg)))) { return NULL; } ast_channel_lock(chan); arg->chan_name = ast_strdup(ast_channel_name(chan)); ast_channel_unlock(chan); if (!arg->chan_name) { hook_thread_arg_destroy(arg); return NULL; } if (ast_asprintf(&arg->hook_id, "%u", state->hook_id) == -1) { hook_thread_arg_destroy(arg); return NULL; } if (!(arg->context = ast_strdup(state->context))) { hook_thread_arg_destroy(arg); return NULL; } if (!(arg->exten = ast_strdup(state->exten))) { hook_thread_arg_destroy(arg); return NULL; } return arg; } static int do_hook(struct ast_channel *chan, struct hook_state *state) { pthread_t t; struct hook_thread_arg *arg; int res; if (!(arg = hook_thread_arg_alloc(chan, state))) { return -1; } /* * We don't want to block normal frame processing *at all* while we kick * this off, so do it in a new thread. */ res = ast_pthread_create_detached_background(&t, NULL, hook_launch_thread, arg); if (res != 0) { hook_thread_arg_destroy(arg); } return res; } static int hook_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction) { struct hook_state *state = (struct hook_state *) audiohook; /* trust me. */ struct timeval now; int res = 0; if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE || state->disabled) { return 0; } now = ast_tvnow(); if (ast_tvdiff_ms(now, state->last_hook) > state->interval * 1000) { if ((res = do_hook(chan, state))) { const char *name; ast_channel_lock(chan); name = ast_strdupa(ast_channel_name(chan)); ast_channel_unlock(chan); ast_log(LOG_WARNING, "Failed to run hook on '%s'\n", name); } state->last_hook = now; } return res; } static struct hook_state *hook_state_alloc(const char *context, const char *exten, unsigned int interval, unsigned int hook_id) { struct hook_state *state; if (!(state = ast_calloc(1, sizeof(*state)))) { return NULL; } state->context = ast_strdup(context); state->exten = ast_strdup(exten); state->interval = interval; state->hook_id = hook_id; ast_audiohook_init(&state->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, AST_MODULE, AST_AUDIOHOOK_MANIPULATE_ALL_RATES); state->audiohook.manipulate_callback = hook_callback; return state; } static int init_hook(struct ast_channel *chan, const char *context, const char *exten, unsigned int interval, unsigned int hook_id) { struct hook_state *state; struct ast_datastore *datastore; char uid[32]; snprintf(uid, sizeof(uid), "%u", hook_id); if (!(datastore = ast_datastore_alloc(&hook_datastore, uid))) { return -1; } ast_module_ref(ast_module_info->self); if (!(state = hook_state_alloc(context, exten, interval, hook_id))) { ast_datastore_free(datastore); return -1; } datastore->data = state; ast_channel_lock(chan); ast_channel_datastore_add(chan, datastore); ast_audiohook_attach(chan, &state->audiohook); ast_channel_unlock(chan); return 0; } static int hook_on(struct ast_channel *chan, const char *data, unsigned int hook_id) { char *parse = ast_strdupa(S_OR(data, "")); AST_DECLARE_APP_ARGS(args, AST_APP_ARG(context); AST_APP_ARG(exten); AST_APP_ARG(interval); );
static int manager_mutestream(struct mansession *s, const struct message *m) { const char *channel = astman_get_header(m, "Channel"); const char *id = astman_get_header(m,"ActionID"); const char *state = astman_get_header(m,"State"); const char *direction = astman_get_header(m,"Direction"); char id_text[256]; struct ast_channel *c = NULL; struct ast_datastore *datastore = NULL; struct mute_information *mute = NULL; int is_new = 0; int turnon; if (ast_strlen_zero(channel)) { astman_send_error(s, m, "Channel not specified"); return 0; } if (ast_strlen_zero(state)) { astman_send_error(s, m, "State not specified"); return 0; } if (ast_strlen_zero(direction)) { astman_send_error(s, m, "Direction not specified"); return 0; } /* Ok, we have everything */ c = ast_channel_get_by_name(channel); if (!c) { astman_send_error(s, m, "No such channel"); return 0; } ast_channel_lock(c); if (!(datastore = ast_channel_datastore_find(c, &mute_datastore, NULL))) { if (!(datastore = initialize_mutehook(c))) { ast_channel_unlock(c); ast_channel_unref(c); astman_send_error(s, m, "Memory allocation failure"); return 0; } is_new = 1; } mute = datastore->data; turnon = ast_true(state); if (!strcasecmp(direction, "in")) { mute->mute_read = turnon; } else if (!strcasecmp(direction, "out")) { mute->mute_write = turnon; } else if (!strcasecmp(direction, "all")) { mute->mute_read = mute->mute_write = turnon; } if (is_new) { if (mute_add_audiohook(c, mute, datastore)) { /* Can't add audiohook */ ast_datastore_free(datastore); ast_free(mute); ast_channel_unlock(c); ast_channel_unref(c); astman_send_error(s, m, "Couldn't add mute audiohook"); return 0; } } ast_channel_unlock(c); ast_channel_unref(c); if (!ast_strlen_zero(id)) { snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id); } else { id_text[0] = '\0'; } astman_append(s, "Response: Success\r\n" "%s" "\r\n", id_text); return 0; }
static int speex_write(struct ast_channel *chan, const char *cmd, char *data, const char *value) { struct ast_datastore *datastore = NULL; struct speex_info *si = NULL; struct speex_direction_info **sdi = NULL; int is_new = 0; ast_channel_lock(chan); if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) { ast_channel_unlock(chan); if (!(datastore = ast_datastore_alloc(&speex_datastore, NULL))) { return 0; } if (!(si = ast_calloc(1, sizeof(*si)))) { ast_datastore_free(datastore); return 0; } ast_audiohook_init(&si->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "speex", AST_AUDIOHOOK_MANIPULATE_ALL_RATES); si->audiohook.manipulate_callback = speex_callback; si->lastrate = 8000; is_new = 1; } else { ast_channel_unlock(chan); si = datastore->data; } if (!strcasecmp(data, "rx")) { sdi = &si->rx; } else if (!strcasecmp(data, "tx")) { sdi = &si->tx; } else { ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd); if (is_new) { ast_datastore_free(datastore); return -1; } } if (!*sdi) { if (!(*sdi = ast_calloc(1, sizeof(**sdi)))) { return 0; } /* Right now, the audiohooks API will _only_ provide us 8 kHz slinear * audio. When it supports 16 kHz (or any other sample rates, we will * have to take that into account here. */ (*sdi)->samples = -1; } if (!strcasecmp(cmd, "agc")) { if (!sscanf(value, "%30f", &(*sdi)->agclevel)) (*sdi)->agclevel = ast_true(value) ? DEFAULT_AGC_LEVEL : 0.0; if ((*sdi)->agclevel > 32768.0) { ast_log(LOG_WARNING, "AGC(%s)=%.01f is greater than 32768... setting to 32768 instead\n", ((*sdi == si->rx) ? "rx" : "tx"), (*sdi)->agclevel); (*sdi)->agclevel = 32768.0; } (*sdi)->agc = !!((*sdi)->agclevel); if ((*sdi)->state) { speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC, &(*sdi)->agc); if ((*sdi)->agc) { speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &(*sdi)->agclevel); } } } else if (!strcasecmp(cmd, "denoise")) { (*sdi)->denoise = (ast_true(value) != 0); if ((*sdi)->state) { speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_DENOISE, &(*sdi)->denoise); } } if (!(*sdi)->agc && !(*sdi)->denoise) { if ((*sdi)->state) speex_preprocess_state_destroy((*sdi)->state); ast_free(*sdi); *sdi = NULL; } if (!si->rx && !si->tx) { if (is_new) { is_new = 0; } else { ast_channel_lock(chan); ast_channel_datastore_remove(chan, datastore); ast_channel_unlock(chan); ast_audiohook_remove(chan, &si->audiohook); ast_audiohook_detach(&si->audiohook); } ast_datastore_free(datastore); } if (is_new) { datastore->data = si; ast_channel_lock(chan); ast_channel_datastore_add(chan, datastore); ast_channel_unlock(chan); ast_audiohook_attach(chan, &si->audiohook); } return 0; }
void ast_jb_create_framehook(struct ast_channel *chan, struct ast_jb_conf *jb_conf, int prefer_existing) { struct jb_framedata *framedata; struct ast_datastore *datastore = NULL; struct ast_framehook_interface interface = { .version = AST_FRAMEHOOK_INTERFACE_VERSION, .event_cb = hook_event_cb, .destroy_cb = hook_destroy_cb, }; int i = 0; /* If disabled, strip any existing jitterbuffer and don't replace it. */ if (!strcasecmp(jb_conf->impl, "disabled")) { int *id; ast_channel_lock(chan); if ((datastore = ast_channel_datastore_find(chan, &jb_datastore, NULL))) { id = datastore->data; ast_framehook_detach(chan, *id); ast_channel_datastore_remove(chan, datastore); ast_datastore_free(datastore); } ast_channel_unlock(chan); return; } if (!(framedata = ast_calloc(1, sizeof(*framedata)))) { return; } if (jb_framedata_init(framedata, jb_conf)) { jb_framedata_destroy(framedata); return; } interface.data = framedata; ast_channel_lock(chan); i = ast_framehook_attach(chan, &interface); if (i >= 0) { int *id; if ((datastore = ast_channel_datastore_find(chan, &jb_datastore, NULL))) { /* There is already a jitterbuffer on the channel. */ if (prefer_existing) { /* We prefer the existing jitterbuffer, so remove the new one and keep the old one. */ ast_framehook_detach(chan, i); ast_channel_unlock(chan); return; } /* We prefer the new jitterbuffer, so strip the old one. */ id = datastore->data; ast_framehook_detach(chan, *id); ast_channel_datastore_remove(chan, datastore); ast_datastore_free(datastore); } if (!(datastore = ast_datastore_alloc(&jb_datastore, NULL))) { ast_framehook_detach(chan, i); ast_channel_unlock(chan); return; } if (!(id = ast_calloc(1, sizeof(int)))) { ast_datastore_free(datastore); ast_framehook_detach(chan, i); ast_channel_unlock(chan); return; } *id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */ datastore->data = id; ast_channel_datastore_add(chan, datastore); ast_channel_set_fd(chan, AST_JITTERBUFFER_FD, framedata->timer_fd); } else { jb_framedata_destroy(framedata); framedata = NULL; } ast_channel_unlock(chan); }
int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target) { struct ast_party_connected_line connected_caller; struct ast_datastore *ds_pickup; const char *chan_name;/*!< A masquerade changes channel names. */ const char *target_name;/*!< A masquerade changes channel names. */ int res = -1; RAII_VAR(struct ast_channel_snapshot *, chan_snapshot, NULL, ao2_cleanup); RAII_VAR(struct ast_channel_snapshot *, target_snapshot, NULL, ao2_cleanup); target_name = ast_strdupa(ast_channel_name(target)); ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, ast_channel_name(chan)); /* Mark the target to block any call pickup race. */ ds_pickup = ast_datastore_alloc(&pickup_active, NULL); if (!ds_pickup) { ast_log(LOG_WARNING, "Unable to create channel datastore on '%s' for call pickup\n", target_name); return -1; } ast_channel_datastore_add(target, ds_pickup); ast_party_connected_line_init(&connected_caller); ast_party_connected_line_copy(&connected_caller, ast_channel_connected(target)); ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */ /* Reset any earlier private connected id representation */ ast_party_id_reset(&connected_caller.priv); connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; if (ast_channel_connected_line_sub(NULL, chan, &connected_caller, 0) && ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { ast_channel_update_connected_line(chan, &connected_caller, NULL); } ast_party_connected_line_free(&connected_caller); ast_channel_lock(chan); chan_name = ast_strdupa(ast_channel_name(chan)); ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(chan)); ast_channel_unlock(chan); connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; if (ast_answer(chan)) { ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name); goto pickup_failed; } if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name); goto pickup_failed; } ast_channel_queue_connected_line_update(chan, &connected_caller, NULL); /* setting the HANGUPCAUSE so the ringing channel knows this call was not a missed call */ ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE); ast_channel_lock(chan); chan_snapshot = ast_channel_snapshot_create(chan); ast_channel_unlock(chan); if (!chan_snapshot) { goto pickup_failed; } target_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(target)); if (!target_snapshot) { goto pickup_failed; } if (ast_channel_move(target, chan)) { ast_log(LOG_WARNING, "Unable to complete call pickup of '%s' with '%s'\n", chan_name, target_name); goto pickup_failed; } /* target points to the channel that did the pickup at this point, so use that channel's topic instead of chan */ send_call_pickup_stasis_message(target, chan_snapshot, target_snapshot); res = 0; pickup_failed: ast_channel_lock(target); if (!ast_channel_datastore_remove(target, ds_pickup)) { ast_datastore_free(ds_pickup); } ast_party_connected_line_free(&connected_caller); return res; }
/*! * \brief Get the lua_State for this channel * * If no channel is passed then a new state is allocated. States with no * channel assocatied with them should only be used for matching extensions. * If the channel does not yet have a lua state associated with it, one will be * created. * * \note If no channel was passed then the caller is expected to free the state * using lua_close(). * * \return a lua_State */ static lua_State *lua_get_state(struct ast_channel *chan) { struct ast_datastore *datastore = NULL; lua_State *L; if (!chan) { L = luaL_newstate(); if (!L) { ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n"); return NULL; } if (lua_load_extensions(L, NULL)) { const char *error = lua_tostring(L, -1); ast_log(LOG_ERROR, "Error loading extensions.lua: %s\n", error); lua_close(L); return NULL; } return L; } else { ast_channel_lock(chan); datastore = ast_channel_datastore_find(chan, &lua_datastore, NULL); ast_channel_unlock(chan); if (!datastore) { /* nothing found, allocate a new lua state */ datastore = ast_datastore_alloc(&lua_datastore, NULL); if (!datastore) { ast_log(LOG_ERROR, "Error allocation channel datastore for lua_State\n"); return NULL; } datastore->data = luaL_newstate(); if (!datastore->data) { ast_datastore_free(datastore); ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n"); return NULL; } ast_channel_lock(chan); ast_channel_datastore_add(chan, datastore); ast_channel_unlock(chan); L = datastore->data; if (lua_load_extensions(L, chan)) { const char *error = lua_tostring(L, -1); ast_log(LOG_ERROR, "Error loading extensions.lua for %s: %s\n", ast_channel_name(chan), error); ast_channel_lock(chan); ast_channel_datastore_remove(chan, datastore); ast_channel_unlock(chan); ast_datastore_free(datastore); return NULL; } } return datastore->data; } }
struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event *event) { struct varshead *headp; struct ast_var_t *newvariable; const char *mixed_name; char timebuf[30]; struct ast_channel *tchan; struct ast_cel_event_record record = { .version = AST_CEL_EVENT_RECORD_VERSION, }; struct ast_datastore *datastore; char *app_data; /* do not call ast_channel_alloc because this is not really a real channel */ if (!(tchan = ast_dummy_channel_alloc())) { return NULL; } headp = ast_channel_varshead(tchan); /* first, get the variables from the event */ if (ast_cel_fill_record(event, &record)) { ast_channel_unref(tchan); return NULL; } /* next, fill the channel with their data */ mixed_name = (record.event_type == AST_CEL_USER_DEFINED) ? record.user_defined_name : record.event_name; if ((newvariable = ast_var_assign("eventtype", mixed_name))) { AST_LIST_INSERT_HEAD(headp, newvariable, entries); } if (ast_strlen_zero(cel_dateformat)) { snprintf(timebuf, sizeof(timebuf), "%ld.%06ld", (long) record.event_time.tv_sec, (long) record.event_time.tv_usec); } else { struct ast_tm tm; ast_localtime(&record.event_time, &tm, NULL); ast_strftime(timebuf, sizeof(timebuf), cel_dateformat, &tm); } if ((newvariable = ast_var_assign("eventtime", timebuf))) { AST_LIST_INSERT_HEAD(headp, newvariable, entries); } if ((newvariable = ast_var_assign("eventenum", record.event_name))) { AST_LIST_INSERT_HEAD(headp, newvariable, entries); } if ((newvariable = ast_var_assign("userdeftype", record.user_defined_name))) { AST_LIST_INSERT_HEAD(headp, newvariable, entries); } if ((newvariable = ast_var_assign("eventextra", record.extra))) { AST_LIST_INSERT_HEAD(headp, newvariable, entries); } ast_channel_caller(tchan)->id.name.valid = 1; ast_channel_caller(tchan)->id.name.str = ast_strdup(record.caller_id_name); ast_channel_caller(tchan)->id.number.valid = 1; ast_channel_caller(tchan)->id.number.str = ast_strdup(record.caller_id_num); ast_channel_caller(tchan)->ani.number.valid = 1; ast_channel_caller(tchan)->ani.number.str = ast_strdup(record.caller_id_ani); ast_channel_redirecting(tchan)->from.number.valid = 1; ast_channel_redirecting(tchan)->from.number.str = ast_strdup(record.caller_id_rdnis); ast_channel_dialed(tchan)->number.str = ast_strdup(record.caller_id_dnid); ast_channel_exten_set(tchan, record.extension); ast_channel_context_set(tchan, record.context); ast_channel_name_set(tchan, record.channel_name); ast_channel_uniqueid_set(tchan, record.unique_id); ast_channel_linkedid_set(tchan, record.linked_id); ast_channel_accountcode_set(tchan, record.account_code); ast_channel_peeraccount_set(tchan, record.peer_account); ast_channel_userfield_set(tchan, record.user_field); if ((newvariable = ast_var_assign("BRIDGEPEER", record.peer))) { AST_LIST_INSERT_HEAD(headp, newvariable, entries); } ast_channel_amaflags_set(tchan, record.amaflag); /* We need to store an 'application name' and 'application * data' on the channel for logging purposes, but the channel * structure only provides a place to store pointers, and it * expects these pointers to be pointing to data that does not * need to be freed. This means that the channel's destructor * does not attempt to free any storage that these pointers * point to. However, we can't provide data in that form directly for * these structure members. In order to ensure that these data * elements have a lifetime that matches the channel's * lifetime, we'll put them in a datastore attached to the * channel, and set's the channel's pointers to point into the * datastore. The datastore will then be automatically destroyed * when the channel is destroyed. */ if (!(datastore = ast_datastore_alloc(&fabricated_channel_datastore, NULL))) { ast_channel_unref(tchan); return NULL; } if (!(app_data = ast_malloc(strlen(record.application_name) + strlen(record.application_data) + 2))) { ast_datastore_free(datastore); ast_channel_unref(tchan); return NULL; } ast_channel_appl_set(tchan, strcpy(app_data, record.application_name)); ast_channel_data_set(tchan, strcpy(app_data + strlen(record.application_name) + 1, record.application_data)); datastore->data = app_data; ast_channel_datastore_add(tchan, datastore); return tchan; }