== AsteriskVer0-1-0/AppDial == {{{ Attempts to "dial out" on all the specified channels (each specified by a type and identifier) simultaneously. The first channel that answers "wins", and all the other outgoing channels are hung up. }}} * int load_module(void) * return ast_register_application(app, dial_exec); {{{ struct localuser { struct ast_channel *chan; int stillgoing; int allowredirect; struct localuser *next; }; }}} {{{ \ digit digit digit An octal character code. The numeric code is 3 octal digits. For compatibility with other Unix systems, 8 and 9 are accepted as digits: for example, \008 has the value 010, and \009 the value 011. }}} * static int dial_exec(struct ast_channel *chan, void *data) * struct localuser *outgoing=NULL, *tmp; * peers = strtok(info, "|"); * timeout = strtok(NULL, "|"); * rest = peers; * technology1/number1&technology2/number2... * do { * cur = strtok(rest, "&"); * rest = strtok(NULL, "\128"); * 앞부분의 technology 와 number 을 cur 에 넣고, 나머지 부분을 rest 에 보관하고자 하는 프로그램이나 문제 있음. * tech 와 number 에 technology 와 number 을 assign * tmp = malloc(sizeof(struct localuser)); * tmp->allowredirect = 1; * number 이 BYEXTENSION 이면 number = chan->exten; tmp->allowredirect = 0; * 없어진 option 인듯함. * tmp->chan = ast_request(tech, chan->format, number); * channel 을 생성하지 못하면, free(tmp); continue; * res = ast_call(tmp->chan, number, 0); * call 이 안되면, ast_hangup(tmp->chan); free(tmp); continue; * tmp->stillgoing = -1; * tmp->next = outgoing; * outgoing = tmp; request 와 call 이 성공한 localuser list 를 만듬. * } while(rest); * if (timeout) to = atoi(timeout) * 1000; * else to = -1; * peer = wait_for_answer(chan, outgoing, &to, &allowredir); * outgoing 이 null 인 경우 이전에 조치를 취하는 것이 좋을 듯함. * if (peer) { * hanguptree(outgoing, peer); peer 을 재외한 나머지 channel 을 hangup 시킴. * outgoing = NULL; * res = bridge_call(chan, peer, allowredir); * ast_hangup(peer); * } * out: * hanguptree(outgoing, NULL); * return res; {{{ 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; }}} * struct ast_channel *ast_request(char *type, int format, void *data) * chan = backends; * type 의 channel 을 찾아, chan->requester 가 있으면 이를 수행시킨다. * c = chan->requester(type, format, data); * return c; * int ast_call(struct ast_channel *chan, char *addr, int timeout) * chan->pvt_call 이 있으면 이를 수행시킨다. * res = chan->pvt->call(chan, addr, timeout); * return res; * int ast_hangup(struct ast_channel *chan) * if (chan->stream) ast_stopstream(chan); * if (chan->sched) sched_context_destroy(chan->sched); * if (chan->blocking) Hard hangup called, while fd is blocking * if (chan->pvt->hangup) * res = chan->pvt->hangup(chan); * if (chan->pvt->pvt) Channel '%s' may not have been hung up properly * if (chan->trans) Hard hangup called on '%s' while a translator is in place! * if (chan->pbx) PBX may not have been terminated properly * if (chan->dnid) free(chan->dnid); * if (chan->callerid) free(chan->callerid); * free(chan->pvt); * free(chan); * return res; * static struct ast_channel *ixj_request(char *type, int format, void *data) * static int ixj_call(struct ast_channel *ast, char *dest, int timeout) * p = ast->pvt->pvt; * channel state 가 AST_STATE_DOWN 도 아니고 AST_STATE_RESERVED 도 아니면 * return -1; * ioctl(p->fd, IXJCTL_RING_START); * ast->state = AST_STATE_RINGING; * return 0; * static int ixj_hangup(struct ast_channel *ast) * p = ast->pvt->pvt; * ast->state = AST_STATE_DOWN; * ioctl(p->fd, IXJCTL_REC_STOP) stop recording * ioctl(p->fd, IXJCTL_PLAY_STOP) stop playing * ioctl(p->fd, IXJCTL_RING_STOP) stop ringing * ioctl(p->fd, IXJCTL_CPT_STOP) stop sounds * if (ioctl(p->fd, IXJCTL_HOOKSTATE)) * ioctl(p->fd, IXJCTL_BUSY); * p->lastformat = -1; p->lastinput = -1; p->ministate = 0; p->obuflen = 0; p->dialtone = 0; * ast->pvt->pvt = NULL; * ast->state = AST_STATE_DOWN; * restart_monitor(); * return 0; * static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, int *allowredir) * to 가 -1 인 경우 매끄럽지 못함. * tv.tv_sec = *to / 1000; tv.tv_usec = (*to % 1000) * 1000; * while((tv.tv_sec || tv.tv_usec) && !peer) { * FD_SET(in->fd, &rfds); FD_SET(in->fd, &efds); * o = outgoing; * found = -1; numlines = 0; * while(o) { * if (o->stillgoing) { * CHECK_BLOCKING(o->chan); * FD_SET(o->chan->fd, &rfds); FD_SET(o->chan->fd, &efds); * if (o->chan->fd > found) found = o->chan->fd; * } * numlines++; * o = o->next; * } * input channel 과 request, call 이 성공적인 channel 들을 FD_SET 함. * if (found<0) { * } * if (in->fd > found) found = in->fd; * if (*to > -1) * found = select(found + 1, &rfds, NULL, &efds, &tv); * else * found = select(found + 1, &rfds, NULL, &efds, NULL); * if (found < 0) { * } * o = outgoing; * while(o) { * if (o->stillgoing) { * o->chan->blocking = 0; * if (FD_ISSET(o->chan->fd, &rfds) || FD_ISSET(o->chan->fd, &efds)) { * 입력된 데이타가 있으면 * f = ast_read(o->chan); ixj_read * if (f) { * AST_CONTROL_ANSWER: ringing 인 상태에서 offhook 이면 * peer = o->chan; * AST_CONTROL_BUSY * o->stillgoing = 0; * numbusies++; * AST_CONTROL_RINGING * AST_CONTROL_OFFHOOK * ast_frfree(f); * } else { * o->stillgoing = 0; * } * } * } * o = o->next; * } * if (FD_ISSET(in->fd, &rfds) || FD_ISSET(in->fd, &efds)) { * f = ast_read(in); * 입력된 데이타가 없거나, hangup 이면 * *to=-1; return NULL; * } * } * if (!(tv.tv_sec || tv.tv_usec) && (option_verbose > 2)) * Nobody picked up in %d ms\n * *to = 0; * return peer; {{{ FD_ZERO(fd_set *fdset) : *fdset의 모든 비트를 지운다. FD_SET(int fd, fd_set *fdset) : *fdset 중 소켓 fd에 해당하는 비트를 1로 한다. FD_CLR(int fd, fd_set *fdset) : *fdset 중 소켓 fd에 해당하는 비트를 0으로 한다. FD_ISSET(int fd, fd_set *fdset) : *fdset 중 소켓 fd에 해당하는 비트가 세트되어 있으면 양수값인 fd를 리턴한다. select() 는 FD_SET으로 설정된 fd만을 확인합니다. 그리고 확인 결과 read또는 write 준비가 된 fd를 fdset 내에서 '세트'시킵니다. 따라서 select() 함수 직후에 FD_ISSET으로 특정 fd가 'SET'되었는지 확인할 수 있습니다. }}} * static int bridge_call(struct ast_channel *chan, struct ast_channel *peer, int allowredirect) * struct ast_channel *cs[3]; * if (chan->state != AST_STATE_UP) * if (ast_answer(chan)) * return -1; * cs[0] = chan; * cs[1] = peer; * for (/* ever */;;) { * who = ast_waitfor_n(cs, 2, &to); * f = ast_read(who); * if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) * return -1; * if ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF)) { * if ((f->frametype == AST_FRAME_DTMF) && (who == peer) && allowredirect) { * } else { * if (who == chan) * ast_write(peer, f); * else * ast_write(chan, f); * } * ast_frfree(f); * } else * ast_frfree(f); * cs[2] = cs[0]; cs[0] = cs[1]; cs[1] = cs[2]; * } * return res; * static int ixj_answer(struct ast_channel *ast) * ixj_setup(ast); * ast->rings = 0; * ast->state = AST_STATE_UP; * return 0; * static int ixj_setup(struct ast_channel *ast) * p = ast->pvt->pvt; * ioctl(p->fd, IXJCTL_CPT_STOP); * if (ast->format & AST_FORMAT_G723_1) { * ioctl(p->fd, IXJCTL_REC_STOP); * if (p->lastinput != AST_FORMAT_G723_1) { * p->lastinput = AST_FORMAT_G723_1; * if (ioctl(p->fd, IXJCTL_REC_CODEC, G723_63)) { * Failed to set codec to g723.1 * return -1; * } * } * } else if (ast->format & AST_FORMAT_SLINEAR) { * ioctl(p->fd, IXJCTL_REC_STOP); * if (p->lastinput != AST_FORMAT_SLINEAR) { * p->lastinput = AST_FORMAT_SLINEAR; * if (ioctl(p->fd, IXJCTL_REC_CODEC, LINEAR16)) { * Failed to set codec to signed linear 16 * return -1; * } * } * } else { * Can't do format * return -1; * } * if (ioctl(p->fd, IXJCTL_REC_START)) { * Failed to start recording * return -1; * } * return 0;