#include "asterisk.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <math.h>
#include "asterisk/pbx.h"
#include "asterisk/frame.h"
#include "asterisk/sched.h"
#include "asterisk/options.h"
#include "asterisk/channel.h"
#include "asterisk/audiohook.h"
#include "asterisk/musiconhold.h"
#include "asterisk/logger.h"
#include "asterisk/say.h"
#include "asterisk/file.h"
#include "asterisk/cli.h"
#include "asterisk/translate.h"
#include "asterisk/manager.h"
#include "asterisk/chanvars.h"
#include "asterisk/linkedlists.h"
#include "asterisk/indications.h"
#include "asterisk/monitor.h"
#include "asterisk/causes.h"
#include "asterisk/callerid.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/transcap.h"
#include "asterisk/devicestate.h"
#include "asterisk/sha1.h"
#include "asterisk/threadstorage.h"
#include "asterisk/slinfactory.h"
Include dependency graph for channel.c:

Go to the source code of this file.
Data Structures | |
| struct | ast_cause |
| struct | ast_silence_generator |
| struct | chanlist |
| struct | tonepair_def |
| struct | tonepair_state |
Defines | |
| #define | AST_DEFAULT_EMULATE_DTMF_DURATION 100 |
| #define | AST_MIN_DTMF_DURATION 80 |
| #define | AST_MIN_DTMF_GAP 45 |
| #define | FORMAT "%-10.10s %-40.40s %-12.12s %-12.12s %-12.12s\n" |
| #define | STATE2STR_BUFSIZE 32 |
Functions | |
| static struct ast_frame * | __ast_read (struct ast_channel *chan, int dropaudio) |
| ast_channel * | __ast_request_and_dial (const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh) |
| int | ast_activate_generator (struct ast_channel *chan, struct ast_generator *gen, void *params) |
| int | ast_active_channels (void) |
| returns number of active/allocated channels | |
| int | ast_answer (struct ast_channel *chan) |
| Answer a ringing call. | |
| void | ast_begin_shutdown (int hangup) |
| Initiate system shutdown. | |
| int | ast_best_codec (int fmts) |
| Pick the best audio codec. | |
| ast_channel * | ast_bridged_channel (struct ast_channel *chan) |
| Find bridged channel. | |
| int | ast_call (struct ast_channel *chan, char *addr, int timeout) |
| Make a call. | |
| void | ast_cancel_shutdown (void) |
| Cancel a shutdown in progress. | |
| const char * | ast_cause2str (int cause) |
| Gives the string form of a given hangup cause. | |
| void | ast_change_name (struct ast_channel *chan, char *newname) |
| Change channel name. | |
| ast_channel * | ast_channel_alloc (int needqueue, int state, const char *cid_num, const char *cid_name, const char *acctcode, const char *exten, const char *context, const int amaflag, const char *name_fmt,...) |
| Create a channel structure. | |
| enum ast_bridge_result | ast_channel_bridge (struct ast_channel *c0, struct ast_channel *c1, struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc) |
| Bridge two channels together. | |
| int | ast_channel_cmpwhentohangup (struct ast_channel *chan, time_t offset) |
| Compare a offset with the settings of when to hang a channel up. | |
| int | ast_channel_datastore_add (struct ast_channel *chan, struct ast_datastore *datastore) |
| Add a datastore to a channel. | |
| ast_datastore * | ast_channel_datastore_alloc (const struct ast_datastore_info *info, char *uid) |
| Create a channel datastore structure. | |
| ast_datastore * | ast_channel_datastore_find (struct ast_channel *chan, const struct ast_datastore_info *info, char *uid) |
| Find a datastore on a channel. | |
| int | ast_channel_datastore_free (struct ast_datastore *datastore) |
| Free a channel datastore structure. | |
| int | ast_channel_datastore_inherit (struct ast_channel *from, struct ast_channel *to) |
| Inherit datastores from a parent to a child. | |
| int | ast_channel_datastore_remove (struct ast_channel *chan, struct ast_datastore *datastore) |
| Remove a datastore from a channel. | |
| int | ast_channel_defer_dtmf (struct ast_channel *chan) |
| Set defer DTMF flag on channel. | |
| void | ast_channel_free (struct ast_channel *chan) |
| Free a channel structure. | |
| void | ast_channel_inherit_variables (const struct ast_channel *parent, struct ast_channel *child) |
| Inherits channel variable from parent to child channel. | |
| int | ast_channel_make_compatible (struct ast_channel *chan, struct ast_channel *peer) |
| Makes two channel formats compatible. | |
| int | ast_channel_masquerade (struct ast_channel *original, struct ast_channel *clone) |
| Weird function made for call transfers. | |
| char * | ast_channel_reason2str (int reason) |
| return an english explanation of the code returned thru __ast_request_and_dial's 'outstate' argument | |
| int | ast_channel_register (const struct ast_channel_tech *tech) |
| Register a channel technology (a new channel driver) Called by a channel module to register the kind of channels it supports. | |
| int | ast_channel_sendhtml (struct ast_channel *chan, int subclass, const char *data, int datalen) |
| int | ast_channel_sendurl (struct ast_channel *chan, const char *url) |
| int | ast_channel_setoption (struct ast_channel *chan, int option, void *data, int datalen, int block) |
| Sets an option on a channel. | |
| void | ast_channel_setwhentohangup (struct ast_channel *chan, time_t offset) |
| Set when to hang a channel up. | |
| ast_silence_generator * | ast_channel_start_silence_generator (struct ast_channel *chan) |
| Starts a silence generator on the given channel. | |
| void | ast_channel_stop_silence_generator (struct ast_channel *chan, struct ast_silence_generator *state) |
| Stops a previously-started silence generator on the given channel. | |
| int | ast_channel_supports_html (struct ast_channel *chan) |
| void | ast_channel_undefer_dtmf (struct ast_channel *chan) |
| Unset defer DTMF flag on channel. | |
| void | ast_channel_unregister (const struct ast_channel_tech *tech) |
| Unregister a channel technology. | |
| ast_channel * | ast_channel_walk_locked (const struct ast_channel *prev) |
| Browse channels in use Browse the channels currently in use. | |
| void | ast_channels_init (void) |
| ast_variable * | ast_channeltype_list (void) |
| return an ast_variable list of channeltypes | |
| int | ast_check_hangup (struct ast_channel *chan) |
| Check to see if a channel is needing hang up. | |
| static int | ast_check_hangup_locked (struct ast_channel *chan) |
| void | ast_deactivate_generator (struct ast_channel *chan) |
| int | ast_do_masquerade (struct ast_channel *original) |
| Start masquerading a channel XXX This is a seriously wacked out operation. We're essentially putting the guts of the clone channel into the original channel. Start by killing off the original channel's backend. I'm not sure we're going to keep this function, because while the features are nice, the cost is very high in terms of pure nastiness. XXX. | |
| static enum ast_bridge_result | ast_generic_bridge (struct ast_channel *c0, struct ast_channel *c1, struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc, struct timeval bridge_end) |
| ast_channel * | ast_get_channel_by_exten_locked (const char *exten, const char *context) |
| Get channel by exten (and optionally context) and lock it. | |
| ast_channel * | ast_get_channel_by_name_locked (const char *name) |
| Get channel by name (locks channel). | |
| ast_channel * | ast_get_channel_by_name_prefix_locked (const char *name, const int namelen) |
| Get channel by name prefix (locks channel). | |
| ast_channel_tech * | ast_get_channel_tech (const char *name) |
| Get a channel technology structure by name. | |
| ast_group_t | ast_get_group (const char *s) |
| int | ast_hangup (struct ast_channel *chan) |
| Hang up a channel. | |
| int | ast_indicate (struct ast_channel *chan, int condition) |
| Indicates condition of channel. | |
| int | ast_indicate_data (struct ast_channel *chan, int condition, const void *data, size_t datalen) |
| Indicates condition of channel, with payload. | |
| void | ast_install_music_functions (int(*start_ptr)(struct ast_channel *, const char *, const char *), void(*stop_ptr)(struct ast_channel *), void(*cleanup_ptr)(struct ast_channel *)) |
| int | ast_internal_timing_enabled (struct ast_channel *chan) |
| Check if the channel can run in internal timing mode. | |
| static | AST_LIST_HEAD_NOLOCK_STATIC (backends, chanlist) |
| static | AST_LIST_HEAD_STATIC (channels, ast_channel) |
| void | ast_moh_cleanup (struct ast_channel *chan) |
| int | ast_moh_start (struct ast_channel *chan, const char *mclass, const char *interpclass) |
| Turn on music on hold on a given channel. | |
| void | ast_moh_stop (struct ast_channel *chan) |
| Turn off music on hold on a given channel. | |
| char * | ast_print_group (char *buf, int buflen, ast_group_t group) |
| print call- and pickup groups into buffer | |
| int | ast_prod (struct ast_channel *chan) |
| Send empty audio to prime a channel driver. | |
| int | ast_queue_control (struct ast_channel *chan, enum ast_control_frame_type control) |
| Queue a control frame with payload. | |
| int | ast_queue_control_data (struct ast_channel *chan, enum ast_control_frame_type control, const void *data, size_t datalen) |
| Queue a control frame with payload. | |
| int | ast_queue_frame (struct ast_channel *chan, struct ast_frame *fin) |
| Queue an outgoing frame. | |
| int | ast_queue_hangup (struct ast_channel *chan) |
| Queue a hangup frame. | |
| ast_frame * | ast_read (struct ast_channel *chan) |
| Reads a frame. | |
| static void | ast_read_generator_actions (struct ast_channel *chan, struct ast_frame *f) |
| ast_frame * | ast_read_noaudio (struct ast_channel *chan) |
| Reads a frame, returning AST_FRAME_NULL frame if audio. Read a frame. | |
| int | ast_readstring (struct ast_channel *c, char *s, int len, int timeout, int ftimeout, char *enders) |
| int | ast_readstring_full (struct ast_channel *c, char *s, int len, int timeout, int ftimeout, char *enders, int audiofd, int ctrlfd) |
| int | ast_recvchar (struct ast_channel *chan, int timeout) |
| Receives a text character from a channel. | |
| char * | ast_recvtext (struct ast_channel *chan, int timeout) |
| Receives a text string from a channel Read a string of text from a channel. | |
| ast_channel * | ast_request (const char *type, int format, void *data, int *cause) |
| Requests a channel. | |
| ast_channel * | ast_request_and_dial (const char *type, int format, void *data, int timeout, int *outstate, const char *cidnum, const char *cidname) |
| Request a channel of a given type, with data as optional information used by the low level module and attempt to place a call on it. | |
| int | ast_safe_sleep (struct ast_channel *chan, int ms) |
| Wait for a specied amount of time, looking for hangups. | |
| int | ast_safe_sleep_conditional (struct ast_channel *chan, int ms, int(*cond)(void *), void *data) |
| Wait for a specied amount of time, looking for hangups and a condition argument. | |
| char * | ast_safe_string_alloc (const char *fmt,...) |
| printf the string into a correctly sized mallocd buffer, and return the buffer | |
| int | ast_say_character_str (struct ast_channel *chan, const char *str, const char *ints, const char *lang) |
| int | ast_say_digit_str (struct ast_channel *chan, const char *str, const char *ints, const char *lang) |
| int | ast_say_digits (struct ast_channel *chan, int num, const char *ints, const char *lang) |
| int | ast_say_digits_full (struct ast_channel *chan, int num, const char *ints, const char *lang, int audiofd, int ctrlfd) |
| int | ast_say_enumeration (struct ast_channel *chan, int num, const char *ints, const char *language, const char *options) |
| int | ast_say_number (struct ast_channel *chan, int num, const char *ints, const char *language, const char *options) |
| int | ast_say_phonetic_str (struct ast_channel *chan, const char *str, const char *ints, const char *lang) |
| int | ast_senddigit (struct ast_channel *chan, char digit) |
| Send a DTMF digit to a channel Send a DTMF digit to a channel. | |
| int | ast_senddigit_begin (struct ast_channel *chan, char digit) |
| int | ast_senddigit_end (struct ast_channel *chan, char digit, unsigned int duration) |
| int | ast_sendtext (struct ast_channel *chan, const char *text) |
| Sends text to a channel Write text to a display on a channel. | |
| void | ast_set_callerid (struct ast_channel *chan, const char *callerid, const char *calleridname, const char *ani) |
| int | ast_set_read_format (struct ast_channel *chan, int fmt) |
| Sets read format on channel chan Set read format for channel to whichever component of "format" is best. | |
| void | ast_set_variables (struct ast_channel *chan, struct ast_variable *vars) |
| adds a list of channel variables to a channel | |
| int | ast_set_write_format (struct ast_channel *chan, int fmt) |
| Sets write format on channel chan Set write format for channel to whichever compoent of "format" is best. | |
| int | ast_setstate (struct ast_channel *chan, enum ast_channel_state state) |
| Change the state of a channel. | |
| int | ast_settimeout (struct ast_channel *c, int samples, int(*func)(const void *data), void *data) |
| int | ast_shutting_down (void) |
| Returns non-zero if Asterisk is being shut down. | |
| int | ast_softhangup (struct ast_channel *chan, int cause) |
| Softly hangup up a channel. | |
| int | ast_softhangup_nolock (struct ast_channel *chan, int cause) |
| Softly hangup up a channel (no channel lock). | |
| char * | ast_state2str (enum ast_channel_state state) |
| Gives the string form of a given channel state. | |
| int | ast_str2cause (const char *name) |
| Convert a symbolic hangup cause to number. | |
| AST_THREADSTORAGE (state2str_threadbuf, state2str_threadbuf_init) | |
| int | ast_tonepair (struct ast_channel *chan, int freq1, int freq2, int duration, int vol) |
| int | ast_tonepair_start (struct ast_channel *chan, int freq1, int freq2, int duration, int vol) |
| void | ast_tonepair_stop (struct ast_channel *chan) |
| int | ast_transfer (struct ast_channel *chan, char *dest) |
| Transfer a channel (if supported). Returns -1 on error, 0 if not supported and 1 if supported and requested. | |
| char * | ast_transfercapability2str (int transfercapability) |
| Gives the string form of a given transfer capability. | |
| void | ast_uninstall_music_functions (void) |
| int | ast_waitfor (struct ast_channel *c, int ms) |
| Wait for input on a channel. | |
| ast_channel * | ast_waitfor_n (struct ast_channel **c, int n, int *ms) |
| Waits for input on a group of channels Wait for input on an array of channels for a given # of milliseconds. | |
| int | ast_waitfor_n_fd (int *fds, int n, int *ms, int *exception) |
| Waits for input on an fd This version works on fd's only. Be careful with it. | |
| ast_channel * | ast_waitfor_nandfds (struct ast_channel **c, int n, int *fds, int nfds, int *exception, int *outfd, int *ms) |
| Waits for activity on a group of channels. | |
| int | ast_waitfordigit (struct ast_channel *c, int ms) |
| Waits for a digit. | |
| int | ast_waitfordigit_full (struct ast_channel *c, int ms, int audiofd, int cmdfd) |
| Wait for a digit Same as ast_waitfordigit() with audio fd for outputting read audio and ctrlfd to monitor for reading. | |
| ast_channel * | ast_walk_channel_by_exten_locked (const struct ast_channel *chan, const char *exten, const char *context) |
| Get next channel by exten (and optionally context) and lock it. | |
| ast_channel * | ast_walk_channel_by_name_prefix_locked (const struct ast_channel *chan, const char *name, const int namelen) |
| Get channel by name prefix (locks channel). | |
| int | ast_write (struct ast_channel *chan, struct ast_frame *fr) |
| Write a frame to a channel This function writes the given frame to the indicated channel. | |
| int | ast_write_video (struct ast_channel *chan, struct ast_frame *fr) |
| Write video frame to a channel This function writes the given frame to the indicated channel. | |
| static void | bridge_playfile (struct ast_channel *chan, struct ast_channel *peer, const char *sound, int remain) |
| static struct ast_channel * | channel_find_locked (const struct ast_channel *prev, const char *name, const int namelen, const char *context, const char *exten) |
| Helper function to find channels. | |
| const char * | channelreloadreason2txt (enum channelreloadreason reason) |
| Convert enum channelreloadreason to text string for manager event. | |
| static void | clone_variables (struct ast_channel *original, struct ast_channel *clone) |
| Clone channel variables from 'clone' channel into 'original' channel. | |
| static char * | complete_channeltypes (const char *line, const char *word, int pos, int state) |
| static char * | complete_channeltypes_deprecated (const char *line, const char *word, int pos, int state) |
| static void | free_cid (struct ast_callerid *cid) |
| static void | free_translation (struct ast_channel *clone) |
| static int | generator_force (const void *data) |
| static int | set_format (struct ast_channel *chan, int fmt, int *rawformat, int *format, struct ast_trans_pvt **trans, const int direction) |
| static int | show_channeltype (int fd, int argc, char *argv[]) |
| static int | show_channeltype_deprecated (int fd, int argc, char *argv[]) |
| static int | show_channeltypes (int fd, int argc, char *argv[]) |
| static void * | silence_generator_alloc (struct ast_channel *chan, void *data) |
| static int | silence_generator_generate (struct ast_channel *chan, void *data, int len, int samples) |
| static void | silence_generator_release (struct ast_channel *chan, void *data) |
| static void * | tonepair_alloc (struct ast_channel *chan, void *params) |
| static int | tonepair_generator (struct ast_channel *chan, void *data, int len, int samples) |
| static void | tonepair_release (struct ast_channel *chan, void *params) |
Variables | |
| static void(*) | ast_moh_cleanup_ptr (struct ast_channel *) = NULL |
| static int(*) | ast_moh_start_ptr (struct ast_channel *, const char *, const char *) = NULL |
| static void(*) | ast_moh_stop_ptr (struct ast_channel *) = NULL |
| ast_cause | causes [] |
| static struct ast_cli_entry | cli_channel [] |
| static struct ast_cli_entry | cli_show_channeltype_deprecated |
| static struct ast_cli_entry | cli_show_channeltypes_deprecated |
| unsigned long | global_fin |
| unsigned long | global_fout |
| static struct ast_channel_tech | null_tech |
| static char | show_channeltype_usage [] |
| static char | show_channeltypes_usage [] |
| static int | shutting_down |
| static struct ast_generator | silence_generator |
| static struct ast_generator | tonepair |
| static int | uniqueint |
Definition in file channel.c.
| #define AST_DEFAULT_EMULATE_DTMF_DURATION 100 |
Default amount of time to use when emulating a digit as a begin and end 100ms
Definition at line 91 of file channel.c.
Referenced by __ast_read(), and ast_senddigit().
| #define AST_MIN_DTMF_DURATION 80 |
Minimum allowed digit length - 80ms
Definition at line 94 of file channel.c.
Referenced by __ast_read().
| #define AST_MIN_DTMF_GAP 45 |
Minimum amount of time between the end of the last digit and the beginning of a new one - 45ms
Definition at line 98 of file channel.c.
Referenced by __ast_read().
| #define FORMAT "%-10.10s %-40.40s %-12.12s %-12.12s %-12.12s\n" |
| #define STATE2STR_BUFSIZE 32 |
| static struct ast_frame* __ast_read | ( | struct ast_channel * | chan, | |
| int | dropaudio | |||
| ) | [static] |
Definition at line 1968 of file channel.c.
References ast_channel::_softhangup, ast_channel::_state, ast_channel::alertpipe, AST_AUDIOHOOK_DIRECTION_READ, ast_audiohook_write_list(), ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_ANSWER, AST_CONTROL_HANGUP, ast_deactivate_generator(), AST_DEFAULT_EMULATE_DTMF_DURATION, ast_do_masquerade(), AST_FLAG_DEFER_DTMF, AST_FLAG_EMULATE_DTMF, AST_FLAG_END_DTMF_ONLY, AST_FLAG_EXCEPTION, AST_FLAG_IN_DTMF, AST_FLAG_OUTGOING, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frame_dump(), AST_FRAME_NULL, AST_FRAME_VOICE, ast_frfree, AST_GENERATOR_FD, ast_getformatname(), ast_getformatname_multiple(), AST_LIST_EMPTY, AST_LIST_FIRST, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_NEXT, AST_LIST_REMOVE_HEAD, ast_log(), AST_MIN_DTMF_DURATION, AST_MIN_DTMF_GAP, AST_MONITOR_RUNNING, ast_null_frame, ast_read_generator_actions(), ast_seekstream(), ast_set_flag, ast_setstate(), AST_SOFTHANGUP_DEV, AST_STATE_UP, ast_strlen_zero(), ast_test_flag, AST_TIMING_FD, ast_translate(), ast_writestream(), ast_channel::audiohooks, ast_channel::blocker, ast_frame::data, DEBUGCHAN_FLAG, ast_channel::dtmf_tv, ast_channel::dtmff, ast_channel::dtmfq, ast_channel::emulate_dtmf_digit, ast_channel::emulate_dtmf_duration, errno, ast_channel_tech::exception, f, ast_channel::fdno, ast_channel::fds, ast_channel::fin, ast_frame::flags, FRAMECOUNT_INC, ast_frame::frametype, func, ast_generator::generate, ast_channel::generator, ast_channel::generatordata, ast_channel::insmpl, LOG_DEBUG, LOG_DTMF, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::masq, ast_channel::monitor, ast_channel::nativeformats, option_debug, ast_channel::outsmpl, ast_channel_tech::read, ast_channel_monitor::read_stream, ast_channel::readtrans, SEEK_FORCECUR, ast_channel_monitor::state, ast_frame::subclass, ast_channel::tech, ast_channel::timingdata, ast_channel::timingfd, and ast_channel::timingfunc.
Referenced by ast_read(), and ast_read_noaudio().
01969 { 01970 struct ast_frame *f = NULL; /* the return value */ 01971 int blah; 01972 int prestate; 01973 int count = 0; 01974 01975 /* this function is very long so make sure there is only one return 01976 * point at the end (there are only two exceptions to this). 01977 */ 01978 while(ast_channel_trylock(chan)) { 01979 if(count++ > 10) 01980 /*cannot goto done since the channel is not locked*/ 01981 return &ast_null_frame; 01982 usleep(1); 01983 } 01984 01985 if (chan->masq) { 01986 if (ast_do_masquerade(chan)) 01987 ast_log(LOG_WARNING, "Failed to perform masquerade\n"); 01988 else 01989 f = &ast_null_frame; 01990 goto done; 01991 } 01992 01993 /* Stop if we're a zombie or need a soft hangup */ 01994 if (ast_test_flag(chan, AST_FLAG_ZOMBIE) || ast_check_hangup(chan)) { 01995 if (chan->generator) 01996 ast_deactivate_generator(chan); 01997 goto done; 01998 } 01999 prestate = chan->_state; 02000 02001 if (!ast_test_flag(chan, AST_FLAG_DEFER_DTMF | AST_FLAG_EMULATE_DTMF | AST_FLAG_IN_DTMF) && 02002 !ast_strlen_zero(chan->dtmfq) && 02003 (ast_tvzero(chan->dtmf_tv) || ast_tvdiff_ms(ast_tvnow(), chan->dtmf_tv) > AST_MIN_DTMF_GAP) ) { 02004 /* We have DTMF that has been deferred. Return it now */ 02005 chan->dtmff.subclass = chan->dtmfq[0]; 02006 /* Drop first digit from the buffer */ 02007 memmove(chan->dtmfq, chan->dtmfq + 1, sizeof(chan->dtmfq) - 1); 02008 f = &chan->dtmff; 02009 if (ast_test_flag(chan, AST_FLAG_END_DTMF_ONLY)) { 02010 ast_log(LOG_DTMF, "DTMF end emulation of '%c' queued on %s\n", f->subclass, chan->name); 02011 chan->dtmff.frametype = AST_FRAME_DTMF_END; 02012 } else { 02013 ast_log(LOG_DTMF, "DTMF begin emulation of '%c' with duration %d queued on %s\n", f->subclass, AST_DEFAULT_EMULATE_DTMF_DURATION, chan->name); 02014 chan->dtmff.frametype = AST_FRAME_DTMF_BEGIN; 02015 ast_set_flag(chan, AST_FLAG_EMULATE_DTMF); 02016 chan->emulate_dtmf_digit = f->subclass; 02017 chan->emulate_dtmf_duration = AST_DEFAULT_EMULATE_DTMF_DURATION; 02018 } 02019 chan->dtmf_tv = ast_tvnow(); 02020 goto done; 02021 } 02022 02023 /* Read and ignore anything on the alertpipe, but read only 02024 one sizeof(blah) per frame that we send from it */ 02025 if (chan->alertpipe[0] > -1) { 02026 int flags = fcntl(chan->alertpipe[0], F_GETFL); 02027 /* For some odd reason, the alertpipe occasionally loses nonblocking status, 02028 * which immediately causes a deadlock scenario. Detect and prevent this. */ 02029 if ((flags & O_NONBLOCK) == 0) { 02030 ast_log(LOG_ERROR, "Alertpipe on channel %s lost O_NONBLOCK?!!\n", chan->name); 02031 if (fcntl(chan->alertpipe[0], F_SETFL, flags | O_NONBLOCK) < 0) { 02032 ast_log(LOG_WARNING, "Unable to set alertpipe nonblocking! (%d: %s)\n", errno, strerror(errno)); 02033 f = &ast_null_frame; 02034 goto done; 02035 } 02036 } 02037 read(chan->alertpipe[0], &blah, sizeof(blah)); 02038 } 02039 02040 #ifdef HAVE_DAHDI 02041 if (chan->timingfd > -1 && chan->fdno == AST_TIMING_FD && ast_test_flag(chan, AST_FLAG_EXCEPTION)) { 02042 int res; 02043 02044 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 02045 blah = -1; 02046 /* IF we can't get event, assume it's an expired as-per the old interface */ 02047 res = ioctl(chan->timingfd, DAHDI_GETEVENT, &blah); 02048 if (res) 02049 blah = DAHDI_EVENT_TIMER_EXPIRED; 02050 02051 if (blah == DAHDI_EVENT_TIMER_PING) { 02052 if (AST_LIST_EMPTY(&chan->readq) || !AST_LIST_NEXT(AST_LIST_FIRST(&chan->readq), frame_list)) { 02053 /* Acknowledge PONG unless we need it again */ 02054 if (ioctl(chan->timingfd, DAHDI_TIMERPONG, &blah)) { 02055 ast_log(LOG_WARNING, "Failed to pong timer on '%s': %s\n", chan->name, strerror(errno)); 02056 } 02057 } 02058 } else if (blah == DAHDI_EVENT_TIMER_EXPIRED) { 02059 ioctl(chan->timingfd, DAHDI_TIMERACK, &blah); 02060 if (chan->timingfunc) { 02061 /* save a copy of func/data before unlocking the channel */ 02062 int (*func)(const void *) = chan->timingfunc; 02063 void *data = chan->timingdata; 02064 ast_channel_unlock(chan); 02065 func(data); 02066 } else { 02067 blah = 0; 02068 ioctl(chan->timingfd, DAHDI_TIMERCONFIG, &blah); 02069 chan->timingdata = NULL; 02070 ast_channel_unlock(chan); 02071 } 02072 /* cannot 'goto done' because the channel is already unlocked */ 02073 return &ast_null_frame; 02074 } else 02075 ast_log(LOG_NOTICE, "No/unknown event '%d' on timer for '%s'?\n", blah, chan->name); 02076 } else 02077 #endif 02078 if (chan->fds[AST_GENERATOR_FD] > -1 && chan->fdno == AST_GENERATOR_FD) { 02079 /* if the AST_GENERATOR_FD is set, call the generator with args 02080 * set to -1 so it can do whatever it needs to. 02081 */ 02082 void *tmp = chan->generatordata; 02083 chan->generatordata = NULL; /* reset to let ast_write get through */ 02084 chan->generator->generate(chan, tmp, -1, -1); 02085 chan->generatordata = tmp; 02086 f = &ast_null_frame; 02087 goto done; 02088 } 02089 02090 /* Check for pending read queue */ 02091 if (!AST_LIST_EMPTY(&chan->readq)) { 02092 f = AST_LIST_REMOVE_HEAD(&chan->readq, frame_list); 02093 /* Interpret hangup and return NULL */ 02094 /* XXX why not the same for frames from the channel ? */ 02095 if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP) { 02096 ast_frfree(f); 02097 f = NULL; 02098 } 02099 } else { 02100 chan->blocker = pthread_self(); 02101 if (ast_test_flag(chan, AST_FLAG_EXCEPTION)) { 02102 if (chan->tech->exception) 02103 f = chan->tech->exception(chan); 02104 else { 02105 ast_log(LOG_WARNING, "Exception flag set on '%s', but no exception handler\n", chan->name); 02106 f = &ast_null_frame; 02107 } 02108 /* Clear the exception flag */ 02109 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 02110 } else if (chan->tech->read) 02111 f = chan->tech->read(chan); 02112 else 02113 ast_log(LOG_WARNING, "No read routine on channel %s\n", chan->name); 02114 } 02115 02116 if (f) { 02117 /* if the channel driver returned more than one frame, stuff the excess 02118 into the readq for the next ast_read call (note that we can safely assume 02119 that the readq is empty, because otherwise we would not have called into 02120 the channel driver and f would be only a single frame) 02121 */ 02122 if (AST_LIST_NEXT(f, frame_list)) { 02123 AST_LIST_HEAD_SET_NOLOCK(&chan->readq, AST_LIST_NEXT(f, frame_list)); 02124 AST_LIST_NEXT(f, frame_list) = NULL; 02125 } 02126 02127 switch (f->frametype) { 02128 case AST_FRAME_CONTROL: 02129 if (f->subclass == AST_CONTROL_ANSWER) { 02130 if (!ast_test_flag(chan, AST_FLAG_OUTGOING)) { 02131 if (option_debug) 02132 ast_log(LOG_DEBUG, "Ignoring answer on an inbound call!\n"); 02133 ast_frfree(f); 02134 f = &ast_null_frame; 02135 } else if (prestate == AST_STATE_UP) { 02136 if (option_debug) 02137 ast_log(LOG_DEBUG, "Dropping duplicate answer!\n"); 02138 ast_frfree(f); 02139 f = &ast_null_frame; 02140 } else { 02141 /* Answer the CDR */ 02142 ast_setstate(chan, AST_STATE_UP); 02143 /* removed a call to ast_cdr_answer(chan->cdr) from here. */ 02144 } 02145 } 02146 break; 02147 case AST_FRAME_DTMF_END: 02148 ast_log(LOG_DTMF, "DTMF end '%c' received on %s, duration %ld ms\n", f->subclass, chan->name, f->len); 02149 /* Queue it up if DTMF is deffered, or if DTMF emulation is forced. 02150 * However, only let emulation be forced if the other end cares about BEGIN frames */ 02151 if ( ast_test_flag(chan, AST_FLAG_DEFER_DTMF) || 02152 (ast_test_flag(chan, AST_FLAG_EMULATE_DTMF) && !ast_test_flag(chan, AST_FLAG_END_DTMF_ONLY)) ) { 02153 if (strlen(chan->dtmfq) < sizeof(chan->dtmfq) - 2) { 02154 ast_log(LOG_DTMF, "DTMF end '%c' put into dtmf queue on %s\n", f->subclass, chan->name); 02155 chan->dtmfq[strlen(chan->dtmfq)] = f->subclass; 02156 } else 02157 ast_log(LOG_WARNING, "Dropping deferred DTMF digits on %s\n", chan->name); 02158 ast_frfree(f); 02159 f = &ast_null_frame; 02160 } else if (!ast_test_flag(chan, AST_FLAG_IN_DTMF | AST_FLAG_END_DTMF_ONLY)) { 02161 if (!ast_tvzero(chan->dtmf_tv) && 02162 ast_tvdiff_ms(ast_tvnow(), chan->dtmf_tv) < AST_MIN_DTMF_GAP) { 02163 /* If it hasn't been long enough, defer this digit */ 02164 if (strlen(chan->dtmfq) < sizeof(chan->dtmfq) - 2) { 02165 ast_log(LOG_DTMF, "DTMF end '%c' put into dtmf queue on %s\n", f->subclass, chan->name); 02166 chan->dtmfq[strlen(chan->dtmfq)] = f->subclass; 02167 } else 02168 ast_log(LOG_WARNING, "Dropping deferred DTMF digits on %s\n", chan->name); 02169 ast_frfree(f); 02170 f = &ast_null_frame; 02171 } else { 02172 /* There was no begin, turn this into a begin and send the end later */ 02173 f->frametype = AST_FRAME_DTMF_BEGIN; 02174 ast_set_flag(chan, AST_FLAG_EMULATE_DTMF); 02175 chan->emulate_dtmf_digit = f->subclass; 02176 chan->dtmf_tv = ast_tvnow(); 02177 if (f->len) { 02178 if (f->len > AST_MIN_DTMF_DURATION) 02179 chan->emulate_dtmf_duration = f->len; 02180 else 02181 chan->emulate_dtmf_duration = AST_MIN_DTMF_DURATION; 02182 } else 02183 chan->emulate_dtmf_duration = AST_DEFAULT_EMULATE_DTMF_DURATION; 02184 ast_log(LOG_DTMF, "DTMF begin emulation of '%c' with duration %u queued on %s\n", f->subclass, chan->emulate_dtmf_duration, chan->name); 02185 } 02186 if (chan->audiohooks) { 02187 struct ast_frame *old_frame = f; 02188 f = ast_audiohook_write_list(chan, chan->audiohooks, AST_AUDIOHOOK_DIRECTION_READ, f); 02189 if (old_frame != f) 02190 ast_frfree(old_frame); 02191 } 02192 } else { 02193 struct timeval now = ast_tvnow(); 02194 if (ast_test_flag(chan,