Sat Apr 12 07:12:34 2008

Asterisk developer's documentation


autoservice.c File Reference

Automatic channel service routines. More...

#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"

Include dependency graph for autoservice.c:

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


Detailed Description

Automatic channel service routines.

Author:
Mark Spencer <markster@digium.com>

Definition in file autoservice.c.


Define Documentation

#define MAX_AUTOMONS   256

Definition at line 53 of file autoservice.c.

Referenced by autoservice_run().


Function Documentation

int ast_autoservice_start ( struct ast_channel chan  ) 

Automatically service a channel for us...

Return values:
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...

Return values:
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 }


Variable Documentation

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().


Generated on Sat Apr 12 07:12:34 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.5