前面两小节讲的都是关于asterisk server,接下来就讲一下asterisk client。
开发asterisk client的话,你可以选择用c/c++ 或者是 java。目前我所用的就是java,不过我首先讲一讲c/c++开发asterisk client的简单例子。
iaxclient
你可以到这里去下载最新的libclient: http://www.sourceforgecn.net/Projects/i/ia/iaxclient/
我下载的是iaxclient-2.1beta3 和 iaxclient-2.1beta3-binary-win32,
其中iaxclient-2.1beta3 是src文件和一些sample, iaxclient-2.1beta3-binary-win32将包含libiaxclient.dll,libiaxclient.lib和头文件iaxclient.h
为了使用里面提供的sample,首先应该设置的的project。在vc6中
tools->options->directories 的include 和 lib 路径中加入你刚下载解压后所在的位置。
打开iaxclient-2.1beta3/simpleclient/testcall/testcall.dsw
project->settings->link tab中的library module 中添加 libiaxclient.lib -- 导入符号表
编译运行就可以啦!
运行后你会发现你并不能做任何事,包括打电话和接电话。原来直接不带运行的话是这样的,如果带参数的话将打电话出去。结合上两节所配置的asterisk (iax.conf/sip.conf/extensions.conf)这个打电话的参数应该是 111001:[email protected]/35693480
111001 -> iax.conf 中的section name,也就是iax 客户端得用户名
xxxxx -> iax.conf 中[111001] 注册的密码
xxx.xxx.xxx.xxx -> 该电话所要连接的asterisk server,也就是你之前配置的asterisk server ip地址
35693480 -> 你所拨打出去的电话号码。
这整个运行过程如下:
1. testcall 在asterisk server中注册登陆,identity by your user name and pwd
2. ready to打电话35693480
3. asterisk 通过iax.conf的设置进入extensions.conf的from_iax dialplan
4. 执行该dial plan,通过sip将该电话拨出去 Dial(SIP/${EXTEN}@${2bAcc},30,r)
5. 电话应答或结束
想获得更多的帮助信息,请参考以下网站:
http://iaxclient.sourceforge.net/doc/html/
以下给出我改写后的testcall 原代码:运行该程序可以在command line 中输入.
./testcall 111001:[email protected]/your_phone_num
嘿,你的电话已经响起来啦!^_^
/* testcall.c
* testcall: make a single test call with IAXCLIENT
*
* IAX Support for talking to Asterisk and other Gnophone clients
*
* Copyright (C) 1999, Linux Support Services, Inc.
*
* Mark Spencer <[email protected]>
*
* This program is free software, distributed under the terms of
* the GNU Lesser (Library) General Public License
*/
/* #define PRINTCHUCK //* enable this to indicate chucked incomming packets *// */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <signal.h>
#include "iaxclient.h"
#define LEVEL_INCREMENT 0.10f
/* static int answered_call; */
static char *output_filename = NULL;
static char *username = NULL;
static char *password = NULL;
static char *host = NULL;
int do_levels = 0;
int intercom = 0;
int initialized = 0;
int reg_id = 0;
/* routine called at exit to shutdown audio I/O and close nicely.
NOTE: If all this isnt done, the system doesnt not handle this
cleanly and has to be rebooted. What a pile of doo doo!! */
void killem(void)
{
if (reg_id){
iaxc_unregister(reg_id);
}
if (initialized)
iaxc_shutdown();
return;
}
void signal_handler(int signum)
{
if ( signum == SIGTERM || signum == SIGINT )
{
killem();
exit(0);
}
}
void fatal_error(char *err) {
killem();
fprintf(stderr, "FATAL ERROR: %s/n", err);
exit(1);
}
void mysleep(void)
{
iaxc_millisleep(10);
}
int state_event_callback(struct iaxc_ev_call_state call){
printf("receive call state event: 0X%p/n",call.state);
if((call.state & IAXC_CALL_STATE_RINGING))
{
if(call.state & IAXC_CALL_STATE_OUTGOING)
{
printf("Make outgoing call .../n");
printf("Remote:[%s][%s] Local:[%s][%s]/n",
call.remote,call.remote_name,call.local,call.local_context);
}
else
{
printf("Receiving Incoming Call Request .../n");
printf("Remote:[%s][%s] Local:[%s][%s]/n",
call.remote,call.remote_name,call.local,call.local_context);
if ( intercom )
{
printf("Intercom mode, answer automatically/n");
return iaxc_select_call(call.callNo);
}
}
}
else if(call.state & IAXC_CALL_STATE_COMPLETE )
{
if(call.state & IAXC_CALL_STATE_OUTGOING )
printf("IAX Out conn - Remote:[%s][%s] Local:[%s][%s]/n",
call.remote,call.remote_name,call.local,call.local_context);
else
printf("IAX In conn - Remote:[%s][%s] Local:[%s][%s]/n",
call.remote,call.remote_name,call.local,call.local_context);
}
return 0;
}
int levels_callback(float input, float output) {
if(do_levels) fprintf(stderr, "IN: %f OUT: %f/n", input, output);
return 0;
}
int netstat_callback(struct iaxc_ev_netstats n) {
static int i;
if(i++%25 == 0)
fprintf(stderr, "RTT/t"
"Rjit/tRlos%%/tRlosC/tRpkts/tRdel/tRdrop/tRooo/t"
"Ljit/tLlos%%/tLlosC/tLpkts/tLdel/tLdrop/tLooo/n"
);
fprintf(stderr, "%d/t"
"%d/t%d/t%d/t%d/t%d/t%d/t%d/t"
"%d/t%d/t%d/t%d/t%d/t%d/t%d/n",
n.rtt,
n.remote.jitter,
n.remote.losspct,
n.remote.losscnt,
n.remote.packets,
n.remote.delay,
n.remote.dropped,
n.remote.ooo,
n.local.jitter,
n.local.losspct,
n.local.losscnt,
n.local.packets,
n.local.delay,
n.local.dropped,
n.local.ooo
);
return 0;
}
int reg_state_call_back(struct iaxc_ev_registration reg)
{
printf("/nReg event id:[%d] reply:[0X%p] msg:[%d]/n",reg.id,reg.reply,reg.msgcount);
return 0;
}
int iaxc_callback(iaxc_event e)
{
switch(e.type) {
case IAXC_EVENT_LEVELS:
return levels_callback(e.ev.levels.input, e.ev.levels.output);
case IAXC_EVENT_NETSTAT:
return netstat_callback(e.ev.netstats);
case IAXC_EVENT_TEXT:
return 0; // don't handle
case IAXC_EVENT_STATE:
return state_event_callback(e.ev.call);
case IAXC_EVENT_REGISTRATION:
return reg_state_call_back(e.ev.reg);
default:
return 0; // not handled
}
}
void list_devices()
{
struct iaxc_audio_device *devs;
int nDevs, input, output, ring;
int i;
iaxc_audio_devices_get(&devs,&nDevs, &input, &output, &ring);
for(i=0;i<nDevs;i++) {
fprintf(stderr, "DEVICE ID=%d NAME=%s CAPS=%lx/n", devs[i].devID, devs[i].name, devs[i].capabilities);
}
}
void usage()
{
fprintf(stderr, "Usage: testcall [-?] [-v] [-i] [-s SILENCE_THRESHOLD] [-u USERNAME -p PASSWORD -h HOST] dest/n"
" dest - The entity to call in the format of/n"
" [user[:password]]@peer[:portno][/exten[@context]]/n"
);
exit(1);
}
int main(int argc, char **argv)
{
FILE *f;
char c;
int i;
char dest[256],tmpbuff[256];
float silence_threshold = -99.0f;
float level;
f = stdout;
memset(dest,0x00,sizeof(dest));
memset(tmpbuff,0x00,sizeof(tmpbuff));
for(i=1;i<argc;i++)
{
if(argv[i][0] == '-')
{
switch(tolower(argv[i][1]))
{
case '?':
usage();
break;
case 'v':
do_levels = 1;
break;
case 'i':
intercom = 1;
break;
case 's': //silence threshold
if(i+1 >= argc) usage();
silence_threshold = (float)atof(argv[++i]);
break;
case 'u': //username
if(i+1 >= argc) usage();
username = argv[++i];
break;
case 'p': //password
if(i+1 >= argc) usage();
password = argv[++i];
break;
case 'h': //host
if(i+1 >= argc) usage();
host = argv[++i];
break;
default:
usage();
}
} else {
strcpy(dest,argv[i]);
}
}
printf("settings: /n");
printf("/tsilence threshold: %f/n", silence_threshold);
printf("/tlevel output: %s/n", do_levels ? "on" : "off");
/* activate the exit handler */
atexit(killem);
/* install signal handler to catch CRTL-Cs */
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
if ( iaxc_initialize(1) ) // init iax client lib
fatal_error("cannot initialize iaxclient!");
initialized = 1;
// iaxc_set_formats(IAXC_FORMAT_SPEEX,IAXC_FORMAT_ULAW|IAXC_FORMAT_GSM|IAXC_FORMAT_SPEEX);
// iaxc_set_formats(IAXC_FORMAT_SPEEX,IAXC_FORMAT_SPEEX);
iaxc_set_formats(IAXC_FORMAT_GSM,IAXC_FORMAT_GSM);
//iaxc_set_formats(IAXC_FORMAT_ULAW,IAXC_FORMAT_ULAW);
//iaxc_set_formats(IAXC_FORMAT_ULAW,IAXC_FORMAT_ILBC|IAXC_FORMAT_ULAW|IAXC_FORMAT_GSM|IAXC_FORMAT_SPEEX);
// The threshold value in dB. A value of 0.0f effectively mutes audio input.
iaxc_set_silence_threshold(silence_threshold);
list_devices();
//if(do_levels)
iaxc_set_event_callback(iaxc_callback);
fprintf(f, "/n/
TestCall accept some keyboard input while it's running./n/
You must hit 'enter' for your keypresses to be recognized,/n/
although you can type more than one key on a line/n/
/n/
q: hangup and exit./n/
a: answer incoming call/n/
d: dial out number/n/
t: terminate call/n/
0-9 * or #: dial those DTMF digits./n/
g: increase input level/n/
b: decrease input level/n/
h: increase output level/n/
n: decrease output level/n/
Enter: display current audio levels/n");
if(strlen(dest)) {
fprintf(f, "Calling %s/n", dest);
//dest The entity to call in the format of
//[user[:password]]@peer[:portno][/exten[@context]]
iaxc_call(dest);
}
iaxc_start_processing_thread();
if (username && password && host)
{
reg_id = iaxc_register(username, password, host);
if(reg_id == -1)
fprintf(f,"Reg fail: %s %s %s/n",username, password, host);
else
fprintf(f,"Reg OK ID:%d/n",reg_id);
}
/*
Registers the IAXClient instance with an IAX server.
Parameters:
user The username to register as
pass The password to register with
host The address of the host/peer to register with
Returns:
The registration id number upon success; -1 otherwise.
*/
printf("ready for keyboard input/n");
if(output_filename) {
for(;;)
iaxc_millisleep(10*1000);
}
while((c = getc(stdin)))
{
switch (tolower(c))
{
case 'a':
printf("Answering call 0/n");
iaxc_select_call(0);
break;
case 'g':
level = iaxc_input_level_get();
level += LEVEL_INCREMENT;
if ( level > 1.00 ) level = 1.00;
printf("Increasing input level to %f/n", level);
iaxc_input_level_set(level);
break;
case 'b':
level = iaxc_input_level_get();
level -= LEVEL_INCREMENT;
if ( level < 0 ) level = 0.00;
printf("Decreasing input level to %f/n", level);
iaxc_input_level_set(level);
break;
case 'd':
//dial number
printf("input phone number: ");
fflush(stdin);
fgets(dest,sizeof(dest),stdin);
if(dest[strlen(dest)-1] == '/n')
dest[strlen(dest)-1] = '/0';
if(dest[strlen(dest)-1] == '/r')
dest[strlen(dest)-1] = '/0';
printf("call - [%s]",dest);
if(strlen(dest))
{
if(username && password && host)
{
sprintf(tmpbuff,"%s:%s@%s/%s",username,password,host,dest);
strcpy(dest,tmpbuff);
}
iaxc_call(dest);
}
break;
case 'h':
level = iaxc_output_level_get();
level += LEVEL_INCREMENT;
if ( level > 1.00 ) level = 1.00;
printf("Increasing output level to %f/n", level);
iaxc_output_level_set(level);
break;
case 'n':
level = iaxc_output_level_get();
level -= LEVEL_INCREMENT;
if ( level < 0 ) level = 0.00;
printf("Decreasing output level to %f/n", level);
iaxc_output_level_set(level);
break;
case 'q':
printf("Hanging up and exiting/n");
iaxc_dump_call();
iaxc_millisleep(1000);
iaxc_stop_processing_thread();
exit(0);
break;
case 't':
printf("Terminating call 0/n");
iaxc_dump_call();
break;
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9': case '0':
case '#': case '*':
printf ("sending %c/n", c);
iaxc_send_dtmf(c);
break;
case '/r':
break;
case '/n':
printf("Input level = %f -- Output level = %f/n", iaxc_input_level_get(), iaxc_output_level_get());
break;
default:
printf("Unknown command '%c'/n", c);
}
}
return 0;
}