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



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
  • 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);
  • }

* 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

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.

There will be big changes for you but you will be happy.

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.0081 sec