· KLDP.org · KLDP.net · KLDP Wiki · KLDP BBS ·
Asterisk Ver0-2-0/App Queue

AsteriskVer0-2-0/AppQueue


queue_exec

static char *descrip =
"  Queue(queuename[|timeout[|options]]):\n"
"Queues an incoming call in a particular call queue as defined in queues.conf.\n"
"  This application returns -1 if the originating channel hangs up, or if the\n"
"call is bridged and  either of the parties in the bridge terminate the call.\n"
"Returns 0 if the queue is full, nonexistant, or has no members.\n"
"The option string may contain zero or more of the following characters:\n"
"      't' -- allow the called user transfer the calling user\n"
"      'T' -- to allow the calling user to transfer the call.\n"
"      'd' -- data-quality (modem) call (minimum delay).\n"
"      'H' -- allow caller to hang up by hitting *.\n"
"  In addition to transferring the call, a call may be parked and then picked\n"
"up by another user.\n";

* queue_exec
  • LOCAL_USER_ADD(u);
  • qe.start = time(NULL);
  • if (!join_queue(queuename, &qe)) {
    • ast_moh_start(chan, qe.moh);
    • for (;;) {
      • res = wait_our_turn(&qe);
        • qe °¡ queueÀÇ head °¡ µÇ¸é res=0, user °¡ key ¸¦ ´©·ç¸é non-zero
      • if (valid_exit(&qe, res)) break
        • res °¡ extension number ¸é qe->chan->exten ¿¡ assignÇÏ°í loop
        • ¾Æ´Ï¸é break
    • }
    • if (!res) { qe °¡ head ¸é
      • for (;;) {
        • res = try_calling(&qe, options);
        • res °¡ 0 °¡ ¾Æ´Ï¸é break
        • res = wait_a_bit(&qe);
          • digit ÀÌ ¾Æ´Ñ key °¡ ´­·ÁÁö¸é break
          • if (res && valid_exit(&qe, res)) break
      • }
    • }
    • res = 0
    • ast_moh_stop(chan);
    • leave_queue(&qe);
  • } else {
    • ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
  • }
  • LOCAL_USER_REMOVE(u);

* static int join_queue(char *queuename, struct queue_ent *qe)
  • queues ¿¡¼­ queue name ÀÇ queue ¸¦ ã´Â´Ù.
    • q->members °¡ ÀÖ°í, ¤Ô¤¢¤È¤¢Â÷Áö ¾Ê¾ÒÀ¸¸é queue ¿¡ ³Ö´Â´Ù.
  • success return 0, error return -1

* static int wait_our_turn(struct queue_ent *qe)
  • qe->parent->head °¡ µÉ¶§±îÁö ±â´Ù¸°´Ù.
  • res = ast_waitfordigit(qe->chan, RECHECK * 1000); 1ÃÊ°£°ÝÀ¸·Î
    • ÀÔ·ÂÀÌ ¾øÀ¸¸é 0, digit °¡ press µÇ¸é digit, ¿À·ù¸é -1
  • ´ÜÁö queue ¿¡¼­ ÀÚ½ÅÀÇ Â÷·Ê¸¦ ±â´Ù¸®´Â °ÍÀÓ.
  • member(or agent) ÀÇ »óÅÂÁ¡°ËÀº try_calling ¿¡¼­ ÇÔ.

* ast_waitfordigit: ast function
  • ms µ¿¾È ÀÔ·ÂÀÌ ¾øÀ¸¸é 0, digit °¡ press µÇ¸é digit, ¿À·ù¸é -1 return

* wait_a_bit
  • retrywait = qe->parent->retry * 1000
  • return ast_waitfordigit(qe->chan, retrywait)

* static int try_calling(struct queue_ent *qe, char *options)
  • cur = qe->parent->members;
  • while(cur) {
    • tmp->chan = ast_request(cur->tech, qe->chan->nativeformats, numsubst);
    • res = ast_call(tmp->chan, numsubst, 0);
  • }
  • peer = wait_for_answer(qe->chan, outgoing, &to, &allowredir, &allowdisconnect, qe->parent->name);
  • if (peer) {
    • hanguptree(outgoing, peer);
    • ast_moh_stop(qe->chan);
    • res = ast_channel_make_compatible(qe->chan, peer);
    • leave_queue(qe);
    • res = ast_bridge_call(qe->chan, peer, allowredir, allowdisconnect);
    • ast_hangup(peer);
  • }
  • out:
  • hanguptree(outgoing, NULL);
  • return res;

* ast_request
  • channellist ¿¡ type ¿¡ ÇØ´çÇÏ´Â channel ÀÌ µî·ÏµÇ¾î ÀÖ´ÂÁö, nativeformats À» Áö¿øÇÏ´ÂÁö Á¡°Ë.
  • numsubst
  • c = chan->requester(type, capabilities, data);
  • return c
ast_request is a wrapper function which causes a channel driver to create a new channel. If the channel we are requesting is currently in use, ringing, busy, or any of the other states > 1, then we know that the channel driver will refuse our request. This is why we only attempt to request a new channel if the device state is currently unknown or not in use.

uses ast_call() to place outgoing call, then goes into wait_for_answer();
   wait_for_answer() loops until answered or timeout.
   uses ast_waitfor_n() to get free channel in the group.
   reads the channel frame (ast_read()) to check for AST_CONTROL_ANSWER (as long as AST_FRAME_CONTROL is on).

channel register and request 0.2.0

struct chanlist {
        char type[80];
        char description[80];
        int capabilities;
        struct ast_channel * (*requester)(char *type, int format, void *data);
        struct chanlist *next;
} *backends = NULL;

* int ast_channel_register(char *type, char *description, int capabilities,
struct ast_channel *(*requester)(char *type, int format, void *data))
  • channel list ¿¡ lock À» °É¼ö ¾øÀ¸¸é return -1;
  • chan = backends;
  • while(chan) {
    • µî·ÏµÈ type À̸é return -1;
  • }
  • ¾øÀ¸¸é chan = malloc(sizeof(struct chanlist));
  • memory alloc °¡ ¾ÈµÇ¸é return -1;
  • channellist struct ¿¡ type, description, capabilities, requester À» assign
  • ¸Ç ³¡¿¡ »õ·Î¿î channel À» assign
  • return 0;

* struct ast_channel *ast_request(char *type, int format, void *data)
  • struct ast_channel *c = NULL;
  • channel list ¿¡ lock À» °É¼ö ¾øÀ¸¸ç return NULL;
  • chan = backends;
  • while(chan) {
    • if (!strcasecmp(type, chan->type)) {
      • res = ast_translator_best_choice(&fmt, &capabilities);
      • capabilities ¿¡ fmt °¡ ¾øÀ¸¸é return NULL;
      • if (chan->requester)
        • c = chan->requester(type, capabilities, data);
      • if (c)
        • manager_event
    • }
    • chan = chan->next; ¸Â´Â type À» ãÀ»¶§°¡Áö while loop
  • }
  • return c;

ast_call 0.2.0

* zt_new, sip_new assign pvt
struct ast_channel_pvt {
        /*! Private data used by channel backend */
        void *pvt;
        struct ast_frame *readq;
        int alertpipe[2];
        /*! Write translation path */
        struct ast_trans_pvt *writetrans;
        /*! Read translation path */
        struct ast_trans_pvt *readtrans;
        /*! Raw read format */
        int rawreadformat;
        /*! Raw write format */
        int rawwriteformat;
        /*! Send a literal DTMF digit */
        int (*send_digit)(struct ast_channel *chan, char digit);
        /*! Call a given phone number (address, etc), but don't
           take longer than timeout seconds to do so.  */
        int (*call)(struct ast_channel *chan, char *addr, int timeout);
        /*! Hangup (and possibly destroy) the channel */
        int (*hangup)(struct ast_channel *chan);
        /*! Answer the line */
        int (*answer)(struct ast_channel *chan);
        /*! Read a frame, in standard format */
        struct ast_frame * (*read)(struct ast_channel *chan);
        /*! Write a frame, in standard format */
        int (*write)(struct ast_channel *chan, struct ast_frame *frame);
        /*! Display or transmit text */
        int (*send_text)(struct ast_channel *chan, char *text);
        /*! Display or send an image */
        int (*send_image)(struct ast_channel *chan, struct ast_frame *frame);
        /*! Send HTML data */
        int (*send_html)(struct ast_channel *chan, int subclass, char *data, int len);
        /*! Handle an exception, reading a frame */
        struct ast_frame * (*exception)(struct ast_channel *chan);
        /*! Bridge two channels of the same type together */
        int (*bridge)(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
        /*! Indicate a particular condition (e.g. AST_CONTROL_BUSY or AST_CONTROL_RINGING or AST_CONTROL_CONGESTION */
        int (*indicate)(struct ast_channel *c, int condition);
        /*! Fix up a channel:  If a channel is consumed, this is called.  Basically update any ->owner links */
        int (*fixup)(struct ast_channel *oldchan, struct ast_channel *newchan);
        /*! Set a given option */
        int (*setoption)(struct ast_channel *chan, int option, void *data, int datalen);
        /*! Query a given option */
        int (*queryoption)(struct ast_channel *chan, int option, void *data, int *datalen);
};

        /* Place an outgoing call, but don't wait any longer than timeout ms before returning. 
           If the remote end does not answer within the timeout, then do NOT hang up, but 
           return anyway.  */
* int ast_call(struct ast_channel *chan, char *addr, int timeout)
  • int res = -1;
  • if (!chan->zombie && !ast_check_hangup(chan))
    • if (chan->pvt->call)
      • res = chan->pvt->call(chan, addr, timeout);
  • return res;

what happends when zt_call() returns 0? 
That depends on who is calling ast_call(), which is the one calling
zt_call() when the technology is zapata (chan_zap, chan_dahdi).
ast_call is pretty much just a wrapper to call the technology call
method.

In the case of app_dial.c (application responsible for handling
Dial()), after ast_call, the technology driver has placed a call to
whichever destiny was specified. Then, the caller (in this case
app_dial.c) will typically wait for a response by calling ast_waitfor
or ast_waitfor_n to poll over the descriptor of the channel, when the
channel has data, the app_dial calls ast_read() which ask in turn the
channel driver for an ast_frame structure, which can be of type
control, DTMF, video, voice (see enum ast_frame_type) and then will do
whatever wants to do with each frame, for example, upon reading a
control frame of type AST_CONTROL_RINGING, app_dial will call
ast_indicate() on the calling channel, so the other callee can be
notified that the placed call is in ringing state. 
> 1) Is it safe for zt_call to block while it waits for the dialtone, or
> does it have to go into some sort of new "pre-dialling state", and
> return?
> 
> 2) Is it safe (or sensible) for zt_call to call zt_read to cause the
> DSP processing to occur and detect the dialtone?
> 
> I suspect that neither of the above are possible, otherwise some
> bright spark would have done dialtone detection already :)

You are correct on both counts... for example, app_dial calls zt_call()
indirectly to initiate outbound calls, and may do so on 2, 3, or more
channels at the same time, so it needs those calls to be non-blocking.

You will need to store away the dialing information and spawn a thread
(or have the do_monitor() thread handle this like it does for other
things) to listen to the incoming audio and then trigger the actual
dialing once you have decided that dialtone is present.



sponsored by andamiro
sponsored by cdnetworks
sponsored by HP

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2009-07-14 09:53:38
Processing time 0.0070 sec