#include "asterisk.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include "asterisk/pbx.h"
#include "asterisk/frame.h"
#include "asterisk/sched.h"
#include "asterisk/options.h"
#include "asterisk/channel.h"
#include "asterisk/logger.h"
#include "asterisk/file.h"
#include "asterisk/translate.h"
#include "asterisk/manager.h"
#include "asterisk/chanvars.h"
#include "asterisk/linkedlists.h"
#include "asterisk/indications.h"
#include "asterisk/lock.h"
#include "asterisk/utils.h"
Go to the source code of this file.
Data Structures | |
struct | asent |
Defines | |
#define | MAX_AUTOMONS 256 |
Functions | |
int | ast_autoservice_start (struct ast_channel *chan) |
Automatically service a channel for us... | |
int | ast_autoservice_stop (struct ast_channel *chan) |
Stop servicing a channel for us... | |
static | AST_LIST_HEAD_STATIC (aslist, asent) |
static void * | autoservice_run (void *ign) |
static void | defer_frame (struct ast_channel *chan, struct ast_frame *f) |
Variables | |
static pthread_t | asthread = AST_PTHREADT_NULL |
Definition in file autoservice.c.
#define MAX_AUTOMONS 256 |
int ast_autoservice_start | ( | struct ast_channel * | chan | ) |
Automatically service a channel for us...
0 | success | |
-1 | failure, or the channel is already being autoserviced |
Definition at line 156 of file autoservice.c.
References ast_calloc, ast_channel_lock, ast_channel_unlock, AST_FLAG_END_DTMF_ONLY, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_pthread_create_background, AST_PTHREADT_NULL, ast_set_flag, ast_test_flag, asthread, autoservice_run(), asent::chan, free, LOG_WARNING, asent::orig_end_dtmf_flag, and asent::use_count.
Referenced by _macro_exec(), acf_curl_exec(), acf_cut_exec(), acf_odbc_read(), acf_odbc_write(), array(), ast_dtmf_stream(), ast_get_enum(), ast_get_srv(), ast_get_txt(), bridge_playfile(), builtin_atxfer(), builtin_automonitor(), builtin_blindtransfer(), conf_play(), feature_exec_app(), function_eval(), function_fieldqty(), function_realtime_read(), function_realtime_write(), osplookup_exec(), pbx_find_extension(), sla_station_exec(), system_exec_helper(), and try_calling().
00157 { 00158 int res = 0; 00159 struct asent *as; 00160 00161 /* Check if the channel already has autoservice */ 00162 AST_LIST_LOCK(&aslist); 00163 AST_LIST_TRAVERSE(&aslist, as, list) { 00164 if (as->chan == chan) { 00165 as->use_count++; 00166 break; 00167 } 00168 } 00169 AST_LIST_UNLOCK(&aslist); 00170 00171 if (as) { 00172 /* Entry exists, autoservice is already handling this channel */ 00173 return 0; 00174 } 00175 00176 if (!(as = ast_calloc(1, sizeof(*as)))) 00177 return -1; 00178 00179 /* New entry created */ 00180 as->chan = chan; 00181 as->use_count = 1; 00182 00183 ast_channel_lock(chan); 00184 as->orig_end_dtmf_flag = ast_test_flag(chan, AST_FLAG_END_DTMF_ONLY) ? 1 : 0; 00185 if (!as->orig_end_dtmf_flag) 00186 ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY); 00187 ast_channel_unlock(chan); 00188 00189 AST_LIST_LOCK(&aslist); 00190 AST_LIST_INSERT_HEAD(&aslist, as, list); 00191 AST_LIST_UNLOCK(&aslist); 00192 00193 if (asthread == AST_PTHREADT_NULL) { /* need start the thread */ 00194 if (ast_pthread_create_background(&asthread, NULL, autoservice_run, NULL)) { 00195 ast_log(LOG_WARNING, "Unable to create autoservice thread :(\n"); 00196 /* There will only be a single member in the list at this point, 00197 the one we just added. */ 00198 AST_LIST_LOCK(&aslist); 00199 AST_LIST_REMOVE(&aslist, as, list); 00200 AST_LIST_UNLOCK(&aslist); 00201 free(as); 00202 res = -1; 00203 } else 00204 pthread_kill(asthread, SIGURG); 00205 } 00206 00207 return res; 00208 }
int ast_autoservice_stop | ( | struct ast_channel * | chan | ) |
Stop servicing a channel for us...
0 | success | |
-1 | error, or the channel has been hungup |
Definition at line 210 of file autoservice.c.
References ast_channel::_softhangup, ast_clear_flag, AST_FLAG_BLOCKING, AST_FLAG_END_DTMF_ONLY, ast_frfree, AST_LIST_APPEND_LIST, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_HEAD_NOLOCK, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, AST_PTHREADT_NULL, ast_queue_frame(), ast_test_flag, asthread, asent::chan, f, free, asent::orig_end_dtmf_flag, and asent::use_count.
Referenced by _macro_exec(), acf_curl_exec(), acf_cut_exec(), acf_odbc_read(), acf_odbc_write(), array(), ast_dtmf_stream(), ast_get_enum(), ast_get_srv(), ast_get_txt(), ast_hangup(), bridge_playfile(), builtin_atxfer(), builtin_automonitor(), conf_play(), feature_exec_app(), finishup(), function_eval(), function_fieldqty(), function_realtime_read(), function_realtime_write(), osplookup_exec(), pbx_find_extension(), sla_station_exec(), system_exec_helper(), and try_calling().
00211 { 00212 int res = -1; 00213 struct asent *as; 00214 AST_LIST_HEAD_NOLOCK(, ast_frame) dtmf_frames; 00215 struct ast_frame *f; 00216 int removed = 0; 00217 int orig_end_dtmf_flag = 0; 00218 00219 AST_LIST_HEAD_INIT_NOLOCK(&dtmf_frames); 00220 00221 AST_LIST_LOCK(&aslist); 00222 AST_LIST_TRAVERSE_SAFE_BEGIN(&aslist, as, list) { 00223 if (as->chan == chan) { 00224 as->use_count--; 00225 if (as->use_count) 00226 break; 00227 AST_LIST_REMOVE_CURRENT(&aslist, list); 00228 AST_LIST_APPEND_LIST(&dtmf_frames, &as->dtmf_frames, frame_list); 00229 orig_end_dtmf_flag = as->orig_end_dtmf_flag; 00230 free(as); 00231 removed = 1; 00232 if (!chan->_softhangup) 00233 res = 0; 00234 break; 00235 } 00236 } 00237 AST_LIST_TRAVERSE_SAFE_END 00238 00239 if (removed && asthread != AST_PTHREADT_NULL) 00240 pthread_kill(asthread, SIGURG); 00241 00242 AST_LIST_UNLOCK(&aslist); 00243 00244 if (!removed) 00245 return 0; 00246 00247 if (!orig_end_dtmf_flag) 00248 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); 00249 00250 /* Wait for it to un-block */ 00251 while (ast_test_flag(chan, AST_FLAG_BLOCKING)) 00252 usleep(1000); 00253 00254 while ((f = AST_LIST_REMOVE_HEAD(&dtmf_frames, frame_list))) { 00255 ast_queue_frame(chan, f); 00256 ast_frfree(f); 00257 } 00258 00259 return res; 00260 }
static AST_LIST_HEAD_STATIC | ( | aslist | , | |
asent | ||||
) | [static] |
static void* autoservice_run | ( | void * | ign | ) | [static] |
Definition at line 85 of file autoservice.c.
References ast_channel::_softhangup, AST_CONTROL_HANGUP, AST_FRAME_CNG, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_HTML, AST_FRAME_IAX, AST_FRAME_IMAGE, AST_FRAME_MODEM, AST_FRAME_NULL, AST_FRAME_TEXT, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_PTHREADT_NULL, ast_read(), ast_waitfor_n(), asthread, asent::chan, defer_frame(), f, ast_frame::frametype, LOG_WARNING, MAX_AUTOMONS, and ast_frame::subclass.
Referenced by ast_autoservice_start().
00086 { 00087 for (;;) { 00088 struct ast_channel *mons[MAX_AUTOMONS]; 00089 struct ast_channel *chan; 00090 struct asent *as; 00091 int x = 0, ms = 500; 00092 00093 AST_LIST_LOCK(&aslist); 00094 AST_LIST_TRAVERSE(&aslist, as, list) { 00095 if (!as->chan->_softhangup) { 00096 if (x < MAX_AUTOMONS) 00097 mons[x++] = as->chan; 00098 else 00099 ast_log(LOG_WARNING, "Exceeded maximum number of automatic monitoring events. Fix autoservice.c\n"); 00100 } 00101 } 00102 AST_LIST_UNLOCK(&aslist); 00103 00104 chan = ast_waitfor_n(mons, x, &ms); 00105 if (chan) { 00106 struct ast_frame *f = ast_read(chan); 00107 00108 if (!f) { 00109 struct ast_frame hangup_frame = { 0, }; 00110 /* No frame means the channel has been hung up. 00111 * A hangup frame needs to be queued here as ast_waitfor() may 00112 * never return again for the condition to be detected outside 00113 * of autoservice. So, we'll leave a HANGUP queued up so the 00114 * thread in charge of this channel will know. */ 00115 00116 hangup_frame.frametype = AST_FRAME_CONTROL; 00117 hangup_frame.subclass = AST_CONTROL_HANGUP; 00118 00119 defer_frame(chan, &hangup_frame); 00120 00121 continue; 00122 } 00123 00124 /* Do not add a default entry in this switch statement. Each new 00125 * frame type should be addressed directly as to whether it should 00126 * be queued up or not. */ 00127 switch (f->frametype) { 00128 /* Save these frames */ 00129 case AST_FRAME_DTMF_END: 00130 case AST_FRAME_CONTROL: 00131 case AST_FRAME_TEXT: 00132 case AST_FRAME_IMAGE: 00133 case AST_FRAME_HTML: 00134 defer_frame(chan, f); 00135 break; 00136 00137 /* Throw these frames away */ 00138 case AST_FRAME_DTMF_BEGIN: 00139 case AST_FRAME_VOICE: 00140 case AST_FRAME_VIDEO: 00141 case AST_FRAME_NULL: 00142 case AST_FRAME_IAX: 00143 case AST_FRAME_CNG: 00144 case AST_FRAME_MODEM: 00145 break; 00146 } 00147 00148 if (f) 00149 ast_frfree(f); 00150 } 00151 } 00152 asthread = AST_PTHREADT_NULL; 00153 return NULL; 00154 }
static void defer_frame | ( | struct ast_channel * | chan, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 70 of file autoservice.c.
References ast_frdup(), AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and asent::chan.
Referenced by autoservice_run().
00071 { 00072 struct ast_frame *dup_f; 00073 struct asent *as; 00074 00075 AST_LIST_LOCK(&aslist); 00076 AST_LIST_TRAVERSE(&aslist, as, list) { 00077 if (as->chan != chan) 00078 continue; 00079 if ((dup_f = ast_frdup(f))) 00080 AST_LIST_INSERT_TAIL(&as->dtmf_frames, dup_f, frame_list); 00081 } 00082 AST_LIST_UNLOCK(&aslist); 00083 }
pthread_t asthread = AST_PTHREADT_NULL [static] |
Definition at line 68 of file autoservice.c.
Referenced by ast_autoservice_start(), ast_autoservice_stop(), and autoservice_run().