Newer
Older
ast_free(doomed->number.str);
doomed->number.str = NULL;
ast_party_subaddress_free(&doomed->subaddress);
}
Mark Michelson
committed
void ast_party_caller_init(struct ast_party_caller *init)
{
ast_party_id_init(&init->id);
ast_party_id_init(&init->ani);
Richard Mudgett
committed
ast_party_id_init(&init->priv);
init->ani2 = 0;
}
void ast_party_caller_copy(struct ast_party_caller *dest, const struct ast_party_caller *src)
{
if (dest == src) {
/* Don't copy to self */
return;
Mark Michelson
committed
}
ast_party_id_copy(&dest->ani, &src->ani);
Richard Mudgett
committed
ast_party_id_copy(&dest->priv, &src->priv);
Mark Michelson
committed
void ast_party_caller_set_init(struct ast_party_caller *init, const struct ast_party_caller *guide)
{
ast_party_id_set_init(&init->id, &guide->id);
ast_party_id_set_init(&init->ani, &guide->ani);
Richard Mudgett
committed
ast_party_id_set_init(&init->priv, &guide->priv);
Mark Michelson
committed
void ast_party_caller_set(struct ast_party_caller *dest, const struct ast_party_caller *src, const struct ast_set_party_caller *update)
{
ast_party_id_set(&dest->id, &src->id, update ? &update->id : NULL);
ast_party_id_set(&dest->ani, &src->ani, update ? &update->ani : NULL);
Richard Mudgett
committed
ast_party_id_set(&dest->priv, &src->priv, update ? &update->priv : NULL);
Mark Michelson
committed
dest->ani2 = src->ani2;
}
void ast_party_caller_free(struct ast_party_caller *doomed)
{
ast_party_id_free(&doomed->id);
ast_party_id_free(&doomed->ani);
Richard Mudgett
committed
ast_party_id_free(&doomed->priv);
Mark Michelson
committed
}
void ast_party_connected_line_init(struct ast_party_connected_line *init)
{
ast_party_id_init(&init->id);
ast_party_id_init(&init->ani);
Richard Mudgett
committed
ast_party_id_init(&init->priv);
Mark Michelson
committed
init->ani2 = 0;
init->source = AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN;
}
void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
{
if (dest == src) {
/* Don't copy to self */
return;
}
ast_party_id_copy(&dest->id, &src->id);
ast_party_id_copy(&dest->ani, &src->ani);
Richard Mudgett
committed
ast_party_id_copy(&dest->priv, &src->priv);
Mark Michelson
committed
dest->ani2 = src->ani2;
dest->source = src->source;
}
void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide)
{
ast_party_id_set_init(&init->id, &guide->id);
ast_party_id_set_init(&init->ani, &guide->ani);
Richard Mudgett
committed
ast_party_id_set_init(&init->priv, &guide->priv);
Mark Michelson
committed
init->ani2 = guide->ani2;
init->source = guide->source;
}
void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src, const struct ast_set_party_connected_line *update)
Mark Michelson
committed
{
ast_party_id_set(&dest->id, &src->id, update ? &update->id : NULL);
ast_party_id_set(&dest->ani, &src->ani, update ? &update->ani : NULL);
Richard Mudgett
committed
ast_party_id_set(&dest->priv, &src->priv, update ? &update->priv : NULL);
Mark Michelson
committed
dest->ani2 = src->ani2;
dest->source = src->source;
}
void ast_party_connected_line_collect_caller(struct ast_party_connected_line *connected, struct ast_party_caller *caller)
Mark Michelson
committed
{
connected->id = caller->id;
connected->ani = caller->ani;
Richard Mudgett
committed
connected->priv = caller->priv;
Mark Michelson
committed
connected->source = AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN;
}
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
{
ast_party_id_free(&doomed->id);
ast_party_id_free(&doomed->ani);
Richard Mudgett
committed
ast_party_id_free(&doomed->priv);
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
void ast_party_redirecting_reason_init(struct ast_party_redirecting_reason *init)
{
init->str = NULL;
init->code = AST_REDIRECTING_REASON_UNKNOWN;
}
void ast_party_redirecting_reason_copy(struct ast_party_redirecting_reason *dest, const struct ast_party_redirecting_reason *src)
{
if (dest == src) {
return;
}
ast_free(dest->str);
dest->str = ast_strdup(src->str);
dest->code = src->code;
}
void ast_party_redirecting_reason_set_init(struct ast_party_redirecting_reason *init, const struct ast_party_redirecting_reason *guide)
{
init->str = NULL;
init->code = guide->code;
}
void ast_party_redirecting_reason_set(struct ast_party_redirecting_reason *dest, const struct ast_party_redirecting_reason *src)
{
if (dest == src) {
return;
}
if (src->str && src->str != dest->str) {
ast_free(dest->str);
dest->str = ast_strdup(src->str);
}
dest->code = src->code;
}
void ast_party_redirecting_reason_free(struct ast_party_redirecting_reason *doomed)
{
ast_free(doomed->str);
}
void ast_party_redirecting_init(struct ast_party_redirecting *init)
{
ast_party_id_init(&init->orig);
ast_party_id_init(&init->from);
ast_party_id_init(&init->to);
Richard Mudgett
committed
ast_party_id_init(&init->priv_orig);
ast_party_id_init(&init->priv_from);
ast_party_id_init(&init->priv_to);
ast_party_redirecting_reason_init(&init->reason);
ast_party_redirecting_reason_init(&init->orig_reason);
Mark Michelson
committed
}
void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src)
{
if (dest == src) {
/* Don't copy to self */
return;
}
ast_party_id_copy(&dest->orig, &src->orig);
Mark Michelson
committed
ast_party_id_copy(&dest->from, &src->from);
ast_party_id_copy(&dest->to, &src->to);
Richard Mudgett
committed
ast_party_id_copy(&dest->priv_orig, &src->priv_orig);
ast_party_id_copy(&dest->priv_from, &src->priv_from);
ast_party_id_copy(&dest->priv_to, &src->priv_to);
ast_party_redirecting_reason_copy(&dest->reason, &src->reason);
ast_party_redirecting_reason_copy(&dest->orig_reason, &src->orig_reason);
Mark Michelson
committed
dest->count = src->count;
}
void ast_party_redirecting_set_init(struct ast_party_redirecting *init, const struct ast_party_redirecting *guide)
{
ast_party_id_set_init(&init->orig, &guide->orig);
Mark Michelson
committed
ast_party_id_set_init(&init->from, &guide->from);
ast_party_id_set_init(&init->to, &guide->to);
Richard Mudgett
committed
ast_party_id_set_init(&init->priv_orig, &guide->priv_orig);
ast_party_id_set_init(&init->priv_from, &guide->priv_from);
ast_party_id_set_init(&init->priv_to, &guide->priv_to);
ast_party_redirecting_reason_set_init(&init->reason, &guide->reason);
ast_party_redirecting_reason_set_init(&init->orig_reason, &guide->orig_reason);
Mark Michelson
committed
init->count = guide->count;
}
void ast_party_redirecting_set(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src, const struct ast_set_party_redirecting *update)
{
ast_party_id_set(&dest->orig, &src->orig, update ? &update->orig : NULL);
ast_party_id_set(&dest->from, &src->from, update ? &update->from : NULL);
ast_party_id_set(&dest->to, &src->to, update ? &update->to : NULL);
Richard Mudgett
committed
ast_party_id_set(&dest->priv_orig, &src->priv_orig, update ? &update->priv_orig : NULL);
ast_party_id_set(&dest->priv_from, &src->priv_from, update ? &update->priv_from : NULL);
ast_party_id_set(&dest->priv_to, &src->priv_to, update ? &update->priv_to : NULL);
ast_party_redirecting_reason_set(&dest->reason, &src->reason);
ast_party_redirecting_reason_set(&dest->orig_reason, &src->orig_reason);
Mark Michelson
committed
void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
{
ast_party_id_free(&doomed->orig);
Mark Michelson
committed
ast_party_id_free(&doomed->from);
ast_party_id_free(&doomed->to);
Richard Mudgett
committed
ast_party_id_free(&doomed->priv_orig);
ast_party_id_free(&doomed->priv_from);
ast_party_id_free(&doomed->priv_to);
ast_party_redirecting_reason_free(&doomed->reason);
ast_party_redirecting_reason_free(&doomed->orig_reason);
Mark Michelson
committed
}
/*! \brief Free a channel structure */
static void ast_channel_destructor(void *obj)
struct ast_channel *chan = obj;
Joshua Colp
committed
#ifdef HAVE_EPOLL
int i;
#endif
struct ast_datastore *datastore;
char device_name[AST_CHANNEL_NAME];
Jonathan Rose
committed
struct ast_callid *callid;
ast_debug(1, "Channel %p '%s' destroying\n", chan, ast_channel_name(chan));
Matthew Jordan
committed
/* Stop monitoring */
if (ast_channel_monitor(chan)) {
ast_channel_monitor(chan)->stop(chan, 0);
}
/* If there is native format music-on-hold state, free it */
if (ast_channel_music_state(chan)) {
ast_moh_cleanup(chan);
}
ast_pbx_hangup_handler_destroy(chan);
/* Things that may possibly raise Stasis messages shouldn't occur after this point */
Matthew Jordan
committed
ast_set_flag(ast_channel_flags(chan), AST_FLAG_DEAD);
if (ast_channel_internal_is_finalized(chan)) {
/* A channel snapshot should not be in the process of being staged now. */
ast_assert(!ast_test_flag(ast_channel_flags(chan), AST_FLAG_SNAPSHOT_STAGE));
ast_channel_lock(chan);
ast_channel_publish_snapshot(chan);
ast_channel_unlock(chan);
publish_cache_clear(chan);
}
Richard Mudgett
committed
/* Get rid of each of the data stores on the channel */
while ((datastore = AST_LIST_REMOVE_HEAD(ast_channel_datastores(chan), entry)))
Kevin P. Fleming
committed
ast_datastore_free(datastore);
Jonathan Rose
committed
/* While the channel is locked, take the reference to its callid while we tear down the call. */
callid = ast_channel_callid(chan);
ast_channel_callid_cleanup(chan);
/* Lock and unlock the channel just to be sure nobody has it locked still
due to a reference that was stored in a datastore. (i.e. app_chanspy) */
ast_channel_lock(chan);
ast_channel_unlock(chan);
if (ast_channel_tech_pvt(chan)) {
Jonathan Rose
committed
ast_log_callid(LOG_WARNING, callid, "Channel '%s' may not have been hung up properly\n", ast_channel_name(chan));
ast_free(ast_channel_tech_pvt(chan));
}
if (ast_channel_sched(chan)) {
ast_sched_context_destroy(ast_channel_sched(chan));
if (ast_channel_internal_is_finalized(chan)) {
ast_copy_string(device_name, ast_channel_name(chan), sizeof(device_name));
if ((dashptr = strrchr(device_name, '-'))) {
*dashptr = '\0';
}
} else {
device_name[0] = '\0';
/* Free translators */
if (ast_channel_readtrans(chan))
ast_translator_free_path(ast_channel_readtrans(chan));
if (ast_channel_writetrans(chan))
ast_translator_free_path(ast_channel_writetrans(chan));
if (ast_channel_pbx(chan))
Jonathan Rose
committed
ast_log_callid(LOG_WARNING, callid, "PBX may not have been terminated properly on '%s'\n", ast_channel_name(chan));
Mark Michelson
committed
/* Free formats */
ast_channel_set_oldwriteformat(chan, NULL);
ast_channel_set_rawreadformat(chan, NULL);
ast_channel_set_rawwriteformat(chan, NULL);
ast_channel_set_readformat(chan, NULL);
ast_channel_set_writeformat(chan, NULL);
ast_party_dialed_free(ast_channel_dialed(chan));
ast_party_caller_free(ast_channel_caller(chan));
ast_party_connected_line_free(ast_channel_connected(chan));
Joshua Colp
committed
ast_party_connected_line_free(ast_channel_connected_indicated(chan));
ast_party_redirecting_free(ast_channel_redirecting(chan));
Mark Michelson
committed
ast_channel_internal_alertpipe_close(chan);
if (ast_channel_timer(chan)) {
ast_timer_close(ast_channel_timer(chan));
Matthew Jordan
committed
ast_channel_timer_set(chan, NULL);
}
Joshua Colp
committed
#ifdef HAVE_EPOLL
for (i = 0; i < AST_MAX_FDS; i++) {
if (ast_channel_internal_epfd_data(chan, i)) {
ast_free(ast_channel_internal_epfd_data(chan, i));
}
Joshua Colp
committed
}
close(ast_channel_epfd(chan));
Joshua Colp
committed
#endif
while ((f = AST_LIST_REMOVE_HEAD(ast_channel_readq(chan), frame_list)))
/* loop over the variables list, freeing all data and deleting list items */
/* no need to lock the list, as the channel is already locked */
headp = ast_channel_varshead(chan);
Kevin P. Fleming
committed
while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
ast_var_delete(vardata);
ast_app_group_discard(chan);
Russell Bryant
committed
/* Destroy the jitterbuffer */
ast_jb_destroy(chan);
if (ast_channel_cdr(chan)) {
ast_cdr_free(ast_channel_cdr(chan));
ast_channel_cdr_set(chan, NULL);
if (ast_channel_zone(chan)) {
ast_channel_zone_set(chan, ast_tone_zone_unref(ast_channel_zone(chan)));
if (device_name[0]) {
/*
* We have a device name to notify of a new state.
*
* Queue an unknown state, because, while we know that this particular
* instance is dead, we don't know the state of all other possible
* instances.
*/
ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE) ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), device_name);
ast_channel_nativeformats_set(chan, NULL);
Jonathan Rose
committed
if (callid) {
ast_callid_unref(callid);
}
ast_channel_named_callgroups_set(chan, NULL);
ast_channel_named_pickupgroups_set(chan, NULL);
ast_atomic_fetchadd_int(&chancount, -1);
/*! \brief Free a dummy channel structure */
static void ast_dummy_channel_destructor(void *obj)
{
struct ast_channel *chan = obj;
Richard Mudgett
committed
struct ast_datastore *datastore;
struct ast_var_t *vardata;
struct varshead *headp;
Richard Mudgett
committed
ast_pbx_hangup_handler_destroy(chan);
/* Get rid of each of the data stores on the channel */
while ((datastore = AST_LIST_REMOVE_HEAD(ast_channel_datastores(chan), entry))) {
/* Free the data store */
ast_datastore_free(datastore);
}
ast_party_dialed_free(ast_channel_dialed(chan));
ast_party_caller_free(ast_channel_caller(chan));
ast_party_connected_line_free(ast_channel_connected(chan));
Joshua Colp
committed
ast_party_connected_line_free(ast_channel_connected_indicated(chan));
ast_party_redirecting_free(ast_channel_redirecting(chan));
/* loop over the variables list, freeing all data and deleting list items */
/* no need to lock the list, as the channel is already locked */
Richard Mudgett
committed
headp = ast_channel_varshead(chan);
while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
ast_var_delete(vardata);
if (ast_channel_cdr(chan)) {
ast_cdr_free(ast_channel_cdr(chan));
ast_channel_cdr_set(chan, NULL);
struct ast_datastore *ast_channel_datastore_alloc(const struct ast_datastore_info *info, const char *uid)
Joshua Colp
committed
{
Kevin P. Fleming
committed
return ast_datastore_alloc(info, uid);
Joshua Colp
committed
}
int ast_channel_datastore_free(struct ast_datastore *datastore)
{
Kevin P. Fleming
committed
return ast_datastore_free(datastore);
Joshua Colp
committed
}
Tilghman Lesher
committed
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
{
struct ast_datastore *datastore = NULL, *datastore2;
AST_LIST_TRAVERSE(ast_channel_datastores(from), datastore, entry) {
Tilghman Lesher
committed
if (datastore->inheritance > 0) {
Kevin P. Fleming
committed
datastore2 = ast_datastore_alloc(datastore->info, datastore->uid);
Tilghman Lesher
committed
if (datastore2) {
datastore2->data = datastore->info->duplicate ? datastore->info->duplicate(datastore->data) : NULL;
Tilghman Lesher
committed
datastore2->inheritance = datastore->inheritance == DATASTORE_INHERIT_FOREVER ? DATASTORE_INHERIT_FOREVER : datastore->inheritance - 1;
AST_LIST_INSERT_TAIL(ast_channel_datastores(to), datastore2, entry);
Tilghman Lesher
committed
}
}
}
return 0;
}
Joshua Colp
committed
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
{
int res = 0;
AST_LIST_INSERT_HEAD(ast_channel_datastores(chan), datastore, entry);
Joshua Colp
committed
return res;
}
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
{
return AST_LIST_REMOVE(ast_channel_datastores(chan), datastore, entry) ? 0 : -1;
Joshua Colp
committed
}
struct ast_datastore *ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Joshua Colp
committed
{
struct ast_datastore *datastore = NULL;
Joshua Colp
committed
if (info == NULL)
return NULL;
AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
Kevin P. Fleming
committed
if (datastore->info != info) {
continue;
}
if (uid == NULL) {
/* matched by type only */
break;
}
if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
/* Matched by type AND uid */
break;
Joshua Colp
committed
}
}
return datastore;
}
Joshua Colp
committed
/*! Set the file descriptor on the channel */
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
{
#ifdef HAVE_EPOLL
struct epoll_event ev;
struct ast_epoll_data *aed = NULL;
if (ast_channel_fd_isset(chan, which)) {
epoll_ctl(ast_channel_epfd(chan), EPOLL_CTL_DEL, ast_channel_fd(chan, which), &ev);
aed = ast_channel_internal_epfd_data(chan, which);
Joshua Colp
committed
}
/* If this new fd is valid, add it to the epoll */
if (fd > -1) {
if (!aed && (!(aed = ast_calloc(1, sizeof(*aed)))))
return;
ast_channel_internal_epfd_data_set(chan, which, aed);
Joshua Colp
committed
aed->chan = chan;
aed->which = which;
Joshua Colp
committed
ev.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP;
ev.data.ptr = aed;
epoll_ctl(ast_channel_epfd(chan), EPOLL_CTL_ADD, fd, &ev);
Joshua Colp
committed
} else if (aed) {
/* We don't have to keep around this epoll data structure now */
ast_free(aed);
ast_channel_epfd_data_set(chan, which, NULL);
Joshua Colp
committed
}
#endif
ast_channel_internal_fd_set(chan, which, fd);
Joshua Colp
committed
return;
}
/*! Add a channel to an optimized waitfor */
void ast_poll_channel_add(struct ast_channel *chan0, struct ast_channel *chan1)
{
#ifdef HAVE_EPOLL
struct epoll_event ev;
int i = 0;
if (ast_channel_epfd(chan0) == -1)
Joshua Colp
committed
return;
/* Iterate through the file descriptors on chan1, adding them to chan0 */
for (i = 0; i < AST_MAX_FDS; i++) {
if (!ast_channel_fd_isset(chan1, i)) {
Joshua Colp
committed
continue;
Joshua Colp
committed
ev.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP;
ev.data.ptr = ast_channel_internal_epfd_data(chan1, i);
epoll_ctl(ast_channel_epfd(chan0), EPOLL_CTL_ADD, ast_channel_fd(chan1, i), &ev);
Joshua Colp
committed
}
#endif
return;
}
/*! Delete a channel from an optimized waitfor */
void ast_poll_channel_del(struct ast_channel *chan0, struct ast_channel *chan1)
{
#ifdef HAVE_EPOLL
struct epoll_event ev;
int i = 0;
if (ast_channel_epfd(chan0) == -1)
Joshua Colp
committed
return;
for (i = 0; i < AST_MAX_FDS; i++) {
if (!ast_channel_fd_isset(chan1, i)) {
Joshua Colp
committed
continue;
}
epoll_ctl(ast_channel_epfd(chan0), EPOLL_CTL_DEL, ast_channel_fd(chan1, i), &ev);
Joshua Colp
committed
}
#endif
return;
}
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
{
ast_channel_lock(chan);
ast_channel_softhangup_internal_flag_clear(chan, flag);
if (!ast_channel_softhangup_internal_flag(chan)) {
struct ast_frame *fr;
/* If we have completely cleared the softhangup flag,
* then we need to fully abort the hangup process. This requires
* pulling the END_OF_Q frame out of the channel frame queue if it
* still happens to be there. */
fr = AST_LIST_LAST(ast_channel_readq(chan));
if (fr && fr->frametype == AST_FRAME_CONTROL &&
fr->subclass.integer == AST_CONTROL_END_OF_Q) {
AST_LIST_REMOVE(ast_channel_readq(chan), fr, frame_list);
ast_frfree(fr);
}
}
ast_channel_unlock(chan);
}
/*! \brief Softly hangup a channel, don't lock */
int ast_softhangup_nolock(struct ast_channel *chan, int cause)
ast_debug(1, "Soft-Hanging (%#04x) up channel '%s'\n", (unsigned)cause, ast_channel_name(chan));
/* Inform channel driver that we need to be hung up, if it cares */
ast_channel_softhangup_internal_flag_add(chan, cause);
ast_queue_frame(chan, &ast_null_frame);
/* Interrupt any poll call or such */
if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING))
pthread_kill(ast_channel_blocker(chan), SIGURG);
/*! \brief Softly hangup a channel, lock */
int ast_softhangup(struct ast_channel *chan, int cause)
{
RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
blob = ast_json_pack("{s: i, s: b}",
"cause", cause,
"soft", 1);
ast_channel_publish_blob(chan, ast_channel_hangup_request_type(), blob);
static void free_translation(struct ast_channel *clonechan)
if (ast_channel_writetrans(clonechan)) {
ast_translator_free_path(ast_channel_writetrans(clonechan));
}
if (ast_channel_readtrans(clonechan)) {
ast_translator_free_path(ast_channel_readtrans(clonechan));
}
ast_channel_writetrans_set(clonechan, NULL);
ast_channel_readtrans_set(clonechan, NULL);
void ast_set_hangupsource(struct ast_channel *chan, const char *source, int force)
{
Mark Michelson
committed
RAII_VAR(struct ast_channel *, bridge, ast_channel_bridge_peer(chan), ast_channel_cleanup);
ast_channel_lock(chan);
if (force || ast_strlen_zero(ast_channel_hangupsource(chan))) {
ast_channel_hangupsource_set(chan, source);
}
ast_channel_unlock(chan);
if (bridge) {
ast_channel_lock(bridge);
if (force || ast_strlen_zero(ast_channel_hangupsource(bridge))) {
ast_channel_hangupsource_set(bridge, source);
}
ast_channel_unlock(bridge);
}
}
int ast_channel_has_audio_frame_or_monitor(struct ast_channel *chan)
{
return ast_channel_monitor(chan)
|| !ast_audiohook_write_list_empty(ast_channel_audiohooks(chan))
|| !ast_framehook_list_contains_no_active(ast_channel_framehooks(chan));
}
Joshua Colp
committed
int ast_channel_has_hook_requiring_audio(struct ast_channel *chan)
{
return ast_channel_monitor(chan)
|| !ast_audiohook_write_list_empty(ast_channel_audiohooks(chan))
|| !ast_framehook_list_contains_no_active_of_type(ast_channel_framehooks(chan), AST_FRAME_VOICE);
}
static void destroy_hooks(struct ast_channel *chan)
{
if (ast_channel_audiohooks(chan)) {
ast_audiohook_detach_list(ast_channel_audiohooks(chan));
ast_channel_audiohooks_set(chan, NULL);
}
ast_framehook_list_destroy(chan);
}
void ast_hangup(struct ast_channel *chan)
/* Be NULL safe for RAII_VAR() usage. */
if (!chan) {
return;
}
ast_debug(1, "Channel %p '%s' hanging up. Refs: %d\n", chan, ast_channel_name(chan),
ao2_ref(chan, 0));
ast_autoservice_stop(chan);
while (ast_channel_masq(chan) || ast_channel_masqr(chan)) {
CHANNEL_DEADLOCK_AVOIDANCE(chan);
/* Mark as a zombie so a masquerade cannot be setup on this channel. */
Richard Mudgett
committed
ast_set_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE);
ast_channel_unlock(chan);
Richard Mudgett
committed
/*
* XXX if running the hangup handlers here causes problems
* because the handlers take too long to execute, we could move
* the meat of this function into another thread. A thread
* where channels go to die.
*
* If this is done, ast_autoservice_chan_hangup_peer() will no
* longer be needed.
*/
ast_pbx_hangup_handler_run(chan);
ao2_unlink(channels, chan);
ast_channel_lock(chan);
destroy_hooks(chan);
if (ast_channel_stream(chan)) {
ast_closestream(ast_channel_stream(chan));
ast_channel_stream_set(chan, NULL);
if (ast_channel_vstream(chan)) {
ast_closestream(ast_channel_vstream(chan));
ast_channel_vstream_set(chan, NULL);
if (ast_channel_sched(chan)) {
ast_sched_context_destroy(ast_channel_sched(chan));
ast_channel_sched_set(chan, NULL);
if (ast_channel_generatordata(chan)) { /* Clear any tone stuff remaining */
if (ast_channel_generator(chan) && ast_channel_generator(chan)->release) {
ast_channel_generator(chan)->release(chan, ast_channel_generatordata(chan));
ast_channel_generatordata_set(chan, NULL);
ast_channel_generator_set(chan, NULL);
if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING)) {
ast_log(LOG_WARNING, "Hard hangup called by thread %ld on %s, while fd "
"is blocked by thread %ld in procedure %s! Expect a failure\n",
(long) pthread_self(), ast_channel_name(chan), (long)ast_channel_blocker(chan), ast_channel_blockproc(chan));
ast_assert(ast_test_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING) == 0);
Richard Mudgett
committed
if (ast_channel_tech(chan)->hangup) {
ast_channel_tech(chan)->hangup(chan);
/*!
* \internal
* \brief Set channel answered time if not already set.
* \since 13.11.0
*
* \param chan Channel to set answered time.
*
* \return Nothing
*/
static void set_channel_answer_time(struct ast_channel *chan)
{
if (ast_tvzero(ast_channel_answertime(chan))) {
struct timeval answertime;
answertime = ast_tvnow();
ast_channel_answertime_set(chan, &answertime);
}
}
int ast_raw_answer(struct ast_channel *chan)
Kevin P. Fleming
committed
Kevin P. Fleming
committed
Mark Spencer
committed
/* You can't answer an outbound call */
if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING)) {
Mark Spencer
committed
return 0;
Kevin P. Fleming
committed
/* Stop if we're a zombie or need a soft hangup */
if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) || ast_check_hangup(chan)) {
Kevin P. Fleming
committed
/*
* Mark when incoming channel answered so we can know how
* long the channel has been up.
*/
set_channel_answer_time(chan);
Russell Bryant
committed
ast_channel_unlock(chan);
switch (ast_channel_state(chan)) {
Russell Bryant
committed
ast_channel_lock(chan);
if (ast_channel_tech(chan)->answer) {
res = ast_channel_tech(chan)->answer(chan);
Russell Bryant
committed
}
ast_setstate(chan, AST_STATE_UP);
Russell Bryant
committed
ast_channel_unlock(chan);
break;
case AST_STATE_UP:
break;
default:
break;
}
ast_indicate(chan, -1);
return res;
}
int __ast_answer(struct ast_channel *chan, unsigned int delay)
{
int res = 0;
enum ast_channel_state old_state;
old_state = ast_channel_state(chan);
if ((res = ast_raw_answer(chan))) {
return res;
}
switch (old_state) {
case AST_STATE_RINGING:
case AST_STATE_RING:
/* wait for media to start flowing, but don't wait any longer
* than 'delay' or 500 milliseconds, whichever is longer
*/
do {
AST_LIST_HEAD_NOLOCK(, ast_frame) frames;
struct ast_frame *cur;
struct ast_frame *new_frame;
unsigned int done = 0;
AST_LIST_HEAD_INIT_NOLOCK(&frames);
for (;;) {
int ms = ast_remaining_ms(start, timeout_ms);
ms = ast_waitfor(chan, ms);
if (ms < 0) {
ast_log(LOG_WARNING, "Error condition occurred when polling channel %s for a voice frame: %s\n", ast_channel_name(chan), strerror(errno));
break;
}
if (ms == 0) {
ast_debug(2, "Didn't receive a media frame from %s within %u ms of answering. Continuing anyway\n", ast_channel_name(chan), MAX(delay, 500));
break;
}
cur = ast_read(chan);
if (!cur || ((cur->frametype == AST_FRAME_CONTROL) &&
(cur->subclass.integer == AST_CONTROL_HANGUP))) {
if (cur) {
ast_frfree(cur);
res = -1;
ast_debug(2, "Hangup of channel %s detected in answer routine\n", ast_channel_name(chan));
break;
}
if ((new_frame = ast_frisolate(cur)) != cur) {
ast_frfree(cur);
}
AST_LIST_INSERT_HEAD(&frames, new_frame, frame_list);
/* if a specific delay period was requested, continue
* until that delay has passed. don't stop just because
* incoming media has arrived.
*/
if (delay) {
continue;
}
switch (new_frame->frametype) {
/* all of these frametypes qualify as 'media' */
case AST_FRAME_VOICE:
case AST_FRAME_VIDEO:
case AST_FRAME_TEXT:
case AST_FRAME_DTMF_BEGIN:
case AST_FRAME_DTMF_END:
case AST_FRAME_IMAGE:
case AST_FRAME_HTML:
case AST_FRAME_MODEM:
done = 1;
break;
case AST_FRAME_CONTROL:
case AST_FRAME_IAX:
Richard Mudgett
committed
case AST_FRAME_BRIDGE_ACTION:
Mark Michelson
committed
case AST_FRAME_BRIDGE_ACTION_SYNC:
case AST_FRAME_NULL:
case AST_FRAME_CNG:
break;
}
if (done) {
break;
}
Kevin P. Fleming
committed
}
ast_channel_lock(chan);
while ((cur = AST_LIST_REMOVE_HEAD(&frames, frame_list))) {
if (res == 0) {
ast_queue_frame_head(chan, cur);
}
} while (0);
default:
break;
Russell Bryant
committed
int ast_answer(struct ast_channel *chan)
{
return __ast_answer(chan, 0);
}
inline int ast_auto_answer(struct ast_channel *chan)
{
if (ast_channel_state(chan) == AST_STATE_UP) {
/* Already answered */
return 0;
}
return ast_answer(chan);
}
int ast_channel_get_duration(struct ast_channel *chan)
{
ast_assert(NULL != chan);
if (ast_tvzero(ast_channel_creationtime(chan))) {
return 0;
}
return (ast_tvdiff_ms(ast_tvnow(), ast_channel_creationtime(chan)) / 1000);
}
int ast_channel_get_up_time(struct ast_channel *chan)
{
ast_assert(NULL != chan);
if (ast_tvzero(ast_channel_answertime(chan))) {
return 0;
}
return (ast_tvdiff_ms(ast_tvnow(), ast_channel_answertime(chan)) / 1000);
}
Richard Mudgett
committed
static void deactivate_generator_nolock(struct ast_channel *chan)
if (ast_channel_generatordata(chan)) {
Richard Mudgett
committed
struct ast_generator *generator = ast_channel_generator(chan);
if (generator && generator->release) {
generator->release(chan, ast_channel_generatordata(chan));
ast_channel_generatordata_set(chan, NULL);
ast_channel_generator_set(chan, NULL);
Joshua Colp
committed
ast_channel_set_fd(chan, AST_GENERATOR_FD, -1);
ast_clear_flag(ast_channel_flags(chan), AST_FLAG_WRITE_INT);
ast_settimeout(chan, 0, NULL, NULL);
Richard Mudgett
committed
}
void ast_deactivate_generator(struct ast_channel *chan)
{
ast_channel_lock(chan);
deactivate_generator_nolock(chan);
static void generator_write_format_change(struct ast_channel *chan)
{
Richard Mudgett
committed
struct ast_generator *generator;
Richard Mudgett
committed
generator = ast_channel_generator(chan);
if (generator && generator->write_format_change) {
generator->write_format_change(chan, ast_channel_generatordata(chan));
}
ast_channel_unlock(chan);
}
static int generator_force(const void *data)
{
/* Called if generator doesn't have data */
void *tmp;
int res;
int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples) = NULL;