Asterisk 是一个开放源代码的软件VoIP PBX系统, AMI (Asterisk Manager Interface)。是Asterisk的管理接口。通过此接口,可以实现对Asterisk系统的监控和控制。通过调用AMI接口可以灵活的做很多事情,比如调用Asterisk系统AMI接口取得来电号码.
在调用接口前,先查看下新安装的Asterisk PBX系统AMI接口的管理配置,配置在/etc/asterisk/manager.conf
cd /etc/asterisk
cat manager.conf
记下需要的信息用户名,密码及端口号 ,使用vi编辑配置能调用接口的网段 permit 这个参数
在Delphi我们可以用TClientSocket控件进行连接AMI接口服务,拖一个控件到窗口上,配置组件 Address及上一步取得的端口号,这里可以尝试验证是否能连接,将Active设置为True,如果提示错误,请注意检查地址及端口号是否正确,同时注意Asterisk 所在的主机是否开启了防火墙,检查网段
至此是能连接上AMI接口服务了,但是取不到数据,验证一下,确实如此,查资料得知,连接上后需要发送用户名及密码给AMI再次进行权限验证,才能取到数据
procedure TFormAmiMain.Btn_ServerOpenClick(Sender: TObject);
begin
//连接AMI
try
Cs_AMI.Close;
Cs_AMI.ClientType := ctNonBlocking;
Cs_AMI.Address := AMIAddress;
Cs_AMI.Port := AMIPort;
Cs_AMI.Open;
//Cs_AMI.Active := True;
except
on e: Exception do
begin
WriteMainSysLog('注意:连接AsteriskAMI失败.错误:' + E.message);
Application.MessageBox(PChar('注意:连接AsteriskAMI失败.错误:' + E.message), '错误提示', MB_OK + MB_ICONERROR);
// exit;
end;
end;
end;
这里可以验证观察一下,确实取不到数据
下面这里是关键,这里是有一个坑需要处理的
我们需要在 TClientSocket连接上后,给Asterisk AMI接口发送用户名及密码,具体格式如下:
Action:login
UserName:admin
Secret:xxxxxxxx
procedure TFormAmiMain.Cs_AMIConnect(Sender: TObject;
Socket: TCustomWinSocket);
var s: string;
begin
WriteMainSysLog('连接成功。');
WriteMainSysLog('发送登陆AsteriskAMI命令...');
s := 'Action:login' + #13#10
+ 'UserName:' + AMIUser + #13#10
+ 'Secret:' + AMIPwd + #13#10
+ #13#10;
Cs_AMI.Socket.SendText(s);
end;
启动软件,看到有数据
在TClientSocket组件onRead取到数据后,想取得来电号码,需要对接收到的数据进行解析
procedure TFormAmiMain.cs_AMIRead(Sender: TObject;
Socket: TCustomWinSocket);
var
RStr: string;
begin
//粘包 多段数据组合的 ,需分解的
RStr := Socket.ReceiveText;
try
// '***检测弹屏*************');
//弹屏取数
AMIReadCTIPopup(RStr);
//self.Memo1.Lines.Add(RStr);
//'********弹屏取数完毕*************');
//发送数据
//发送完毕
except
end;
end;
解析出来号码的过程
procedure TFormAmiMain.AMIReadCTIPopup(ReceiveText: string);
var
Slt: TStringList;
i, j: integer;
s: string;
SLD: TStringList;
begin
Slt := TStringList.Create;
// self.Memo1.Lines.Add('**********************');
try
SLD := TStringList.Create;
try
SLT.Text := ReceiveText;
for i := 0 to slt.Count - 1 do
begin
// self.Memo1.Lines.Add(Format('%.5d', [i]) + ' ' + SLT.Strings[I]);
s := Trim(SLT.Strings[I]);
//前一行 'ChannelState: 6'
if s = 'ChannelStateDesc: Up' then
begin
{
self.Memo2.Lines.Add('***********************');
self.Memo2.Lines.Add(SLT.Strings[i - 2]);
self.Memo2.Lines.Add(SLT.Strings[i - 1]);
self.Memo2.Lines.Add(SLT.Strings[i]);
self.Memo2.Lines.Add(SLT.Strings[i + 1]);
self.Memo2.Lines.Add(SLT.Strings[i + 2]);
self.Memo2.Lines.Add(SLT.Strings[i + 3]);
self.Memo2.Lines.Add(SLT.Strings[i + 4]);
}
// self.Memo2.Lines.Add('**********************');
{//样式格式
Channel=SIP/1102-000001a0
ChannelState=6
ChannelStateDesc=Up
CallerIDNum=1102
CallerIDName=device
ConnectedLineNum=1109
ConnectedLineName=1109
}
SLD.Clear;
SLD.Add(StringReplace(SLT.Strings[i - 3], ': ', '=', [rfReplaceAll, rfIgnoreCase]));
SLD.Add(StringReplace(SLT.Strings[i - 2], ': ', '=', [rfReplaceAll, rfIgnoreCase]));
SLD.Add(StringReplace(SLT.Strings[i - 1], ': ', '=', [rfReplaceAll, rfIgnoreCase]));
SLD.Add(StringReplace(SLT.Strings[i], ': ', '=', [rfReplaceAll, rfIgnoreCase]));
SLD.Add(StringReplace(SLT.Strings[i + 1], ': ', '=', [rfReplaceAll, rfIgnoreCase]));
SLD.Add(StringReplace(SLT.Strings[i + 2], ': ', '=', [rfReplaceAll, rfIgnoreCase]));
SLD.Add(StringReplace(SLT.Strings[i + 3], ': ', '=', [rfReplaceAll, rfIgnoreCase]));
SLD.Add(StringReplace(SLT.Strings[i + 4], ': ', '=', [rfReplaceAll, rfIgnoreCase]));
// SELF.Memo2.Lines.Add('**************');
// Self.Memo2.Lines.Add(SLD.Text);
if SLD.Values['CallerIDName'] = 'device' then
begin
DBLogAMIPOPUP(DMDB.ADOCon, SLD);
//
{
Self.Memo2.Lines.Add('--被叫--' + SLD.Values['CallerIDNum']);
Self.Memo2.Lines.Add('来电弹屏号码' + SLD.Values['ConnectedLineNum']);
Self.memo2.lines.add('Timestamp Is ::' + SLD.Values['Timestamp']);
Self.memo2.lines.add('Channel Is ::' + SLD.Values['Channel']);
Self.memo2.lines.add('ChannelState Is ::' + SLD.Values['ChannelState']);
Self.memo2.lines.add('ChannelStateDesc Is ::' + SLD.Values['ChannelStateDesc']);
Self.memo2.lines.add('CallerIDNum Is ::' + SLD.Values['CallerIDNum']);
Self.memo2.lines.add('CallerIDName Is ::' + SLD.Values['CallerIDName']);
Self.memo2.lines.add('ConnectedLineNum Is ::' + SLD.Values['ConnectedLineNum']);
Self.memo2.lines.add('ConnectedLineName Is ::' + SLD.Values['ConnectedLineName']);
}
//转发取得的号码消息给客户端
for j := Ss_1.Socket.ActiveConnections - 1 downto 0 do
begin
try
Ss_1.socket.connections[j].sendtext(SLD.Text);
//Ss_1.Socket.Connections[j].RemoteAddress
//WriteMainSysLog(SLD.Text);
except
on E: Exception do
WriteMainSysLog('发送弹屏信息出错,错误:' + E.Message);
end;
end;
end;
{
else
if SLD.Values['ConnectedLineName']= 'device' then
// if SLD.Values['CallerIDName'] 'device' then
begin
//
Self.Memo2.Lines.Add('--主叫--' + SLD.Values['CallerIDNum']);
Self.Memo2.Lines.Add('呼叫号码' + SLD.Values['ConnectedLineNum']);
Self.memo2.lines.add('Timestamp Is ::' + SLD.Values['Timestamp']);
Self.memo2.lines.add('Channel Is ::' + SLD.Values['Channel']);
Self.memo2.lines.add('ChannelState Is ::' + SLD.Values['ChannelState']);
Self.memo2.lines.add('ChannelStateDesc Is ::' + SLD.Values['ChannelStateDesc']);
Self.memo2.lines.add('CallerIDNum Is ::' + SLD.Values['CallerIDNum']);
Self.memo2.lines.add('CallerIDName Is ::' + SLD.Values['CallerIDName']);
Self.memo2.lines.add('ConnectedLineNum Is ::' + SLD.Values['ConnectedLineNum']);
Self.memo2.lines.add('ConnectedLineName Is ::' + SLD.Values['ConnectedLineName']);
end;}
// SELF.Memo2.Lines.Add('**************');
end;
end;
// self.Memo1.Lines.Add('**********************');
finally
SLD.Free;
end;
finally
Slt.Free;
end;
end;
解析出来电号码后,我们就可以用TServerSocket实现转发给客户端了,这种方式实时性非常高
客户端用TClientSocket接收消息
至此我们即能调用AMI取得来电号码了,如果还想进一步用Asterisk AMI 做更多的事,需要更深入了解AMI接口命令行.
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
文章目录 第2章:线性表 (一) 顺序表 1.顺序表的定义、初始化 静态分配 动态分配 2.顺序表的插入 3.顺序表的删除 (二) 链表 1.单链表 1.单链表结点的数据类型定义 2.单链表的建立 头插法 单链表的逆置 (头插法实现) 尾插法 3.单链表结点的…