Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 223490 $")
00031
00032 #include <sys/time.h>
00033 #include <signal.h>
00034
00035 #include "asterisk/_private.h"
00036
00037 #include "asterisk/pbx.h"
00038 #include "asterisk/frame.h"
00039 #include "asterisk/sched.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/file.h"
00042 #include "asterisk/translate.h"
00043 #include "asterisk/manager.h"
00044 #include "asterisk/chanvars.h"
00045 #include "asterisk/linkedlists.h"
00046 #include "asterisk/indications.h"
00047 #include "asterisk/lock.h"
00048 #include "asterisk/utils.h"
00049
00050 #define MAX_AUTOMONS 1500
00051
00052 struct asent {
00053 struct ast_channel *chan;
00054
00055
00056
00057 unsigned int use_count;
00058 unsigned int orig_end_dtmf_flag:1;
00059
00060
00061
00062 AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
00063 AST_LIST_ENTRY(asent) list;
00064 };
00065
00066 static AST_LIST_HEAD_STATIC(aslist, asent);
00067 static ast_cond_t as_cond;
00068
00069 static pthread_t asthread = AST_PTHREADT_NULL;
00070
00071 static int as_chan_list_state;
00072
00073 static void *autoservice_run(void *ign)
00074 {
00075 struct ast_frame hangup_frame = {
00076 .frametype = AST_FRAME_CONTROL,
00077 .subclass = AST_CONTROL_HANGUP,
00078 };
00079
00080 for (;;) {
00081 struct ast_channel *mons[MAX_AUTOMONS];
00082 struct asent *ents[MAX_AUTOMONS];
00083 struct ast_channel *chan;
00084 struct asent *as;
00085 int i, x = 0, ms = 50;
00086 struct ast_frame *f = NULL;
00087 struct ast_frame *defer_frame = NULL;
00088
00089 AST_LIST_LOCK(&aslist);
00090
00091
00092
00093 as_chan_list_state++;
00094
00095 if (AST_LIST_EMPTY(&aslist)) {
00096 ast_cond_wait(&as_cond, &aslist.lock);
00097 }
00098
00099 AST_LIST_TRAVERSE(&aslist, as, list) {
00100 if (!ast_check_hangup(as->chan)) {
00101 if (x < MAX_AUTOMONS) {
00102 ents[x] = as;
00103 mons[x++] = as->chan;
00104 } else {
00105 ast_log(LOG_WARNING, "Exceeded maximum number of automatic monitoring events. Fix autoservice.c\n");
00106 }
00107 }
00108 }
00109
00110 AST_LIST_UNLOCK(&aslist);
00111
00112 if (!x) {
00113 continue;
00114 }
00115
00116 chan = ast_waitfor_n(mons, x, &ms);
00117 if (!chan) {
00118 continue;
00119 }
00120
00121 f = ast_read(chan);
00122
00123 if (!f) {
00124
00125
00126
00127
00128
00129
00130 defer_frame = &hangup_frame;
00131 } else {
00132
00133
00134
00135
00136
00137 switch (f->frametype) {
00138
00139 case AST_FRAME_DTMF_END:
00140 case AST_FRAME_CONTROL:
00141 case AST_FRAME_TEXT:
00142 case AST_FRAME_IMAGE:
00143 case AST_FRAME_HTML:
00144 defer_frame = f;
00145 break;
00146
00147
00148 case AST_FRAME_DTMF_BEGIN:
00149 case AST_FRAME_VOICE:
00150 case AST_FRAME_VIDEO:
00151 case AST_FRAME_NULL:
00152 case AST_FRAME_IAX:
00153 case AST_FRAME_CNG:
00154 case AST_FRAME_MODEM:
00155 break;
00156 }
00157 }
00158
00159 if (defer_frame) {
00160 for (i = 0; i < x; i++) {
00161 struct ast_frame *dup_f;
00162
00163 if (mons[i] != chan) {
00164 continue;
00165 }
00166
00167 if (defer_frame != f) {
00168 if ((dup_f = ast_frdup(defer_frame))) {
00169 AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
00170 }
00171 } else {
00172 if ((dup_f = ast_frisolate(defer_frame))) {
00173 if (dup_f != defer_frame) {
00174 ast_frfree(defer_frame);
00175 }
00176 AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
00177 }
00178 }
00179
00180 break;
00181 }
00182 } else if (f) {
00183 ast_frfree(f);
00184 }
00185 }
00186
00187 asthread = AST_PTHREADT_NULL;
00188
00189 return NULL;
00190 }
00191
00192 int ast_autoservice_start(struct ast_channel *chan)
00193 {
00194 int res = 0;
00195 struct asent *as;
00196
00197 AST_LIST_LOCK(&aslist);
00198 AST_LIST_TRAVERSE(&aslist, as, list) {
00199 if (as->chan == chan) {
00200 as->use_count++;
00201 break;
00202 }
00203 }
00204 AST_LIST_UNLOCK(&aslist);
00205
00206 if (as) {
00207
00208 return 0;
00209 }
00210
00211 if (!(as = ast_calloc(1, sizeof(*as))))
00212 return -1;
00213
00214
00215 as->chan = chan;
00216 as->use_count = 1;
00217
00218 ast_channel_lock(chan);
00219 as->orig_end_dtmf_flag = ast_test_flag(chan, AST_FLAG_END_DTMF_ONLY) ? 1 : 0;
00220 if (!as->orig_end_dtmf_flag)
00221 ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
00222 ast_channel_unlock(chan);
00223
00224 AST_LIST_LOCK(&aslist);
00225
00226 if (AST_LIST_EMPTY(&aslist) && asthread != AST_PTHREADT_NULL) {
00227 ast_cond_signal(&as_cond);
00228 }
00229
00230 AST_LIST_INSERT_HEAD(&aslist, as, list);
00231
00232 if (asthread == AST_PTHREADT_NULL) {
00233 if (ast_pthread_create_background(&asthread, NULL, autoservice_run, NULL)) {
00234 ast_log(LOG_WARNING, "Unable to create autoservice thread :(\n");
00235
00236
00237 AST_LIST_REMOVE(&aslist, as, list);
00238 free(as);
00239 asthread = AST_PTHREADT_NULL;
00240 res = -1;
00241 } else {
00242 pthread_kill(asthread, SIGURG);
00243 }
00244 }
00245
00246 AST_LIST_UNLOCK(&aslist);
00247
00248 return res;
00249 }
00250
00251 int ast_autoservice_stop(struct ast_channel *chan)
00252 {
00253 int res = -1;
00254 struct asent *as, *removed = NULL;
00255 struct ast_frame *f;
00256 int chan_list_state;
00257
00258 AST_LIST_LOCK(&aslist);
00259
00260
00261
00262
00263
00264 chan_list_state = as_chan_list_state;
00265
00266
00267
00268 AST_LIST_TRAVERSE_SAFE_BEGIN(&aslist, as, list) {
00269 if (as->chan == chan) {
00270 as->use_count--;
00271 if (as->use_count < 1) {
00272 AST_LIST_REMOVE_CURRENT(list);
00273 removed = as;
00274 }
00275 break;
00276 }
00277 }
00278 AST_LIST_TRAVERSE_SAFE_END;
00279
00280 if (removed && asthread != AST_PTHREADT_NULL) {
00281 pthread_kill(asthread, SIGURG);
00282 }
00283
00284 AST_LIST_UNLOCK(&aslist);
00285
00286 if (!removed) {
00287 return 0;
00288 }
00289
00290
00291 while (chan_list_state == as_chan_list_state) {
00292 usleep(1000);
00293 }
00294
00295
00296
00297
00298 if (!chan->_softhangup) {
00299 res = 0;
00300 }
00301
00302 if (!as->orig_end_dtmf_flag) {
00303 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00304 }
00305
00306 ast_channel_lock(chan);
00307 while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) {
00308 ast_queue_frame_head(chan, f);
00309 ast_frfree(f);
00310 }
00311 ast_channel_unlock(chan);
00312
00313 free(as);
00314
00315 return res;
00316 }
00317
00318 void ast_autoservice_init(void)
00319 {
00320 ast_cond_init(&as_cond, NULL);
00321 }