Thinkai's Blog

Autohoutkey|Python|php|aardio|VOIP|IT 爱好者

正在浏览分类 VOIP

总共找到 12 篇

Centos/Elastix/Asterisk 引导修复办法 967

作者为 发表

VOIP

首先,我们需要找一个引导,用安装光盘进入恢复模式可能有些问题,所以这次我们用U盘Grub4DOS的方式直接进入系统再修复。

首先需要下载BOOTICEGrub4DOS

插入U盘到电脑,打开BOOTICE,格式化成FAT格式,然后设置主引导记录:

把下载的grub4dos解压,复制grldr和grub.exe到U盘,创建menu.lst,内容如下(具体的启动内核可能不一样):

default=0
timeout=5

title hd1_371
        root (hd1,0)
        kernel /boot/vmlinuz-2.6.18-371.1.2.el5 ro root=LABEL=/
        initrd /boot/initrd-2.6.18-371.1.2.el5.img
title hd1_406
        root (hd1,0)
        kernel /boot/vmlinuz-2.6.18-406.el5 ro root=LABEL=/
        initrd /boot/initrd-2.6.18-406.el5.img
title hd0_371
        root (hd0,0)
        kernel /boot/vmlinuz-2.6.18-371.1.2.el5 ro root=LABEL=/
        initrd /boot/initrd-2.6.18-371.1.2.el5.img
title hd0_406
        root (hd0,0)
        kernel /boot/vmlinuz-2.6.18-406.el5 ro root=LABEL=/
        initrd /boot/initrd-2.6.18-406.el5.img
title hd2_371
        root (hd2,0)
        kernel /boot/vmlinuz-2.6.18-371.1.2.el5 ro root=LABEL=/
        initrd /boot/initrd-2.6.18-371.1.2.el5.img
title hd2_406
        root (hd2,0)
        kernel /boot/vmlinuz-2.6.18-406.el5 ro root=LABEL=/
        initrd /boot/initrd-2.6.18-406.el5.img

设置服务器从U盘启动,尝试启动到系统,进入之后进行修复grub操作

grub-install --root-directory=/boot /dev/hda

这就大功告成了!

自动修改Asterisk的中继的IP Python 1136

作者为 发表

VOIP

由于对接的有个网关定期换IP,手动设定很麻烦。所以写了这么一个脚本扔到cron里。

首先需要修改/etc/asterisk/sip.conf,找到#include sip_custom.conf这里,修改成:

;#include sip_custom.conf
#include sip_additional.conf
#include sip_custom.conf

然后把py脚本整到/bin里:

import re
import os

part_a = '''[9031]
disallow=all
username=9031
type=friend
secret=9031
qualify=yes
insecure=invite
host=dynamic
dtmfmode=rfc2833
context=from-pstn
canreinvite=0
allow=g723

[9031_Out]
disallow=all
username=9031
type=friend
secret=9031
qualify=yes
port=7878
host='''
part_b = '''
fromeuser=9031
context=from-pstn
allow=g723
'''
res = os.popen('asterisk -x "sip show peers"').read()
lines = res.split("\n")

for line in lines:
	if line.find("9031/9031")>-1:
		inbound = re.match("9031/9031\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+D\s+Yes\s+Yes\s+\d+\s+OK \(\d+ ms\)",line)
	elif line.find("9031_Out/9031")>-1:
		outbound = re.match("9031_Out/9031\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+Yes\s+Yes\s+\d+\s+UNREACHABLE",line)
if inbound and outbound and inbound.group(1) <> outbound.group(1):
	print "Change peer IP "+outbound.group(1)+" to "+inbound.group(1)
	f = open("\etc\asterisk\sip_custom.conf","w")
	f.write(part_a+inbound.group(1)+part_b)
	f.close()
	os.popen('asterisk -x reload')
else:
	print "Peer IP has not changed"

再修改/etc/crontab,添加一个定时任务:

*/10 * * * * root python /bin/check_trunk_ip.py

最后重启下crond服务就Ok啦。

service crond restart


修改Elastix文字登陆界面欢迎信息 1087

作者为 发表

VOIP

#移除原文件
rm /etc/motd
#重新创建 按i插入, Esc退出编辑模式,输入:wq保存退出
vi /etc/motd
#设置只读
chmod 444 /etc/motd
#不允许删除
chattr +ia /etc/motd
reboot


环境Elastix2.5

编辑/etc/asterisk/extensions.conf

[from-internal]
exten=>#,1,Answer //这里设置的是#号键
exten=>#,n,MySql(connect connid localhost root 123456 asteriskcdrdb) //连接mysql 操作
;exten=>#,n,MySql(query resultidr ${connid} insert into test (msg) values ('${CALLERID(num)}')) //测试插入
exten=>#,n,MySql(query resultidr ${connid} select dst as a,uniqueid as b from cdr where src=${CALLERID(num)} order by uniqueid desc limit 1) //获取上一个呼叫记录数据
exten=>#,n,MySql(Fetch foundrow ${resultidr} a b) //取出变量
exten=>#,n,MySql(clear ${resultidr}) //清空结果集
exten=>#,n,MySql(query resultidr ${connid} update cdr set userfield='OK' where uniqueid=${b}) //更新
exten=>#,n,MySql(clear ${resultidr})
exten=>#,n,MySql(disconnect ${connid}) //断开连接
exten=>#,n,saydigits(${a}) //报被叫号码
exten=>#,n,Playback(custom/mark_ok) //“已经标记成功”语音
exten=>#,n,Hangup //挂机

//后面是原来的拨号方案
include => from-internal-noxfer
include => from-internal-xfer
include => bad-number ; auto-generated

保存完毕后需要重载asterisk生效。

Asterisk Dialplan拨号方案中的系统变量环境变量 1361

作者为 发表

VOIP

转自cnblogs

asterisk中,定义了许多变量,或是有些变量能够被其读取。下面给出了它们的列表。在每一个application的帮助文档中,你可以获得更多的信息。所有这些变量都是大写的。

*标记的变量是内建函数,不能在拨号方案中被设置,只能被读取。对这些变量的赋值将被忽略。

${CDR(accountcode)}    * Account code (if specified)

${BLINDTRANSFER}         The name of the channel on the other side of a blind transfer

${BRIDGEPEER}            Bridged peer

${BRIDGEPVTCALLID}       Bridged peer PVT call ID (SIP Call ID if a SIP call)

${CALLERID(ani)}       * Caller ANI (PRI channels)

${CALLERID(ani2)}      * ANI2 (Info digits) also called Originating line information or OLI

${CALLERID(all)}       * Caller ID

${CALLERID(dnid)}      * Dialed Number Identifier

${CALLERID(name)}      * Caller ID Name only

${CALLERID(num)}       * Caller ID Number only

${CALLERID(rdnis)}     * Redirected Dial Number ID Service

${CALLINGANI2}         * Caller ANI2 (PRI channels)

${CALLINGPRES}         * Caller ID presentation for incoming calls (PRI channels)

${CALLINGTNS}          * Transit Network Selector (PRI channels)

${CALLINGTON}          * Caller Type of Number (PRI channels)

${CHANNEL}             * Current channel name

${CONTEXT}             * Current context

${DATETIME}            * Current date time in the format: DDMMYYYY-HH:MM:SS

                         (Deprecated; use ${STRFTIME(${EPOCH},,%d%m%Y-%H:%M:%S)})

${DB_RESULT}             Result value of DB_EXISTS() dial plan function

${EPOCH}               * Current unix style epoch

${EXTEN}               * Current extension

${ENV(VAR)}              Environmental variable VAR

${GOTO_ON_BLINDXFR}      Transfer to the specified context/extension/priority

                         after a blind transfer (use ^ characters in place of

                         | to separate context/extension/priority when setting

                         this variable from the dialplan)

${HANGUPCAUSE}         * Asterisk cause of hangup (inbound/outbound)

${HINT}                * Channel hints for this extension

${HINTNAME}            * Suggested Caller*ID name for this extension

${INVALID_EXTEN}         The invalid called extension (used in the "i" extension)

${LANGUAGE}            * Current language (Deprecated; use ${LANGUAGE()})

${LEN(VAR)}            * String length of VAR (integer)

${PRIORITY}            * Current priority in the dialplan

${PRIREDIRECTREASON}     Reason for redirect on PRI, if a call was directed

${TIMESTAMP}           * Current date time in the format: YYYYMMDD-HHMMSS

                         (Deprecated; use ${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)})

${TRANSFER_CONTEXT}      Context for transferred calls

${FORWARD_CONTEXT}       Context for forwarded calls

${UNIQUEID}            * Current call unique identifier

${SYSTEMNAME}          * value of the systemname option of asterisk.conf

${ENTITYID}            * Global Entity ID set automatically, or from asterisk.conf

Application的返回值(Application return values

当你调用有些application的时候,它们会返回一个值供你读取。对于每一个application,这些状态字段是唯一的。各种状态值,前参考每个application的帮助文档。

${AGISTATUS}         * agi()

${AQMSTATUS}         * addqueuemember()

${AVAILSTATUS}       * chanisavail()

${CHECKGROUPSTATUS}  * checkgroup()

${CHECKMD5STATUS}    * checkmd5()

${CPLAYBACKSTATUS}   * controlplayback()

${DIALSTATUS}        * dial()

${DBGETSTATUS}       * dbget()

${ENUMSTATUS}        * enumlookup()

${HASVMSTATUS}       * hasnewvoicemail()

${LOOKUPBLSTATUS}    * lookupblacklist()

${OSPAUTHSTATUS}     * ospauth()

${OSPLOOKUPSTATUS}   * osplookup()

${OSPNEXTSTATUS}     * ospnext()

${OSPFINISHSTATUS}   * ospfinish()

${PARKEDAT}          * parkandannounce()

${PLAYBACKSTATUS}    * playback()

${PQMSTATUS}         * pausequeuemember()

${PRIVACYMGRSTATUS}  * privacymanager()

${QUEUESTATUS}       * queue()

${RQMSTATUS}         * removequeuemember()

${SENDIMAGESTATUS}   * sendimage()

${SENDTEXTSTATUS}    * sendtext()

${SENDURLSTATUS}     * sendurl()

${SYSTEMSTATUS}      * system()

${TRANSFERSTATUS}    * transfer()

${TXTCIDNAMESTATUS}  * txtcidname()

${UPQMSTATUS}        * unpausequeuemember()

${VMSTATUS}          * voicmail()

${VMBOXEXISTSSTATUS} * vmboxexists()

${WAITSTATUS}        * waitforsilence()

各种application的相关变量(Various application variables

${CURL}                 * Resulting page content for curl()

${ENUM}                 * Result of application EnumLookup

${EXITCONTEXT}            Context to exit to in IVR menu (app background())

                          or in the RetryDial() application

${MONITOR}              * Set to "TRUE" if the channel is/has been monitored (app monitor())

${MONITOR_EXEC}           Application to execute after monitoring a call

${MONITOR_EXEC_ARGS}      Arguments to application

${MONITOR_FILENAME}       File for monitoring (recording) calls in queue

${QUEUE_PRIO}             Queue priority

${QUEUE_MAX_PENALTY}      Maximum member penalty allowed to answer caller

${QUEUE_MIN_PENALTY}      Minimum member penalty allowed to answer caller

${QUEUESTATUS}            Status of the call, one of:

                          (TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL)

${RECORDED_FILE}        * Recorded file in record()

${TALK_DETECTED}        * Result from talkdetect()

${TOUCH_MONITOR}          The filename base to use with Touch Monitor (auto record)

${TOUCH_MONITOR_PREF}   * The prefix for automonitor recording filenames.

${TOUCH_MONITOR_FORMAT}   The audio format to use with Touch Monitor (auto record)

${TOUCH_MONITOR_OUTPUT} * Recorded file from Touch Monitor (auto record)

${TOUCH_MONITOR_MESSAGE_START} Recorded file to play for both channels at start of monitoring session

${TOUCH_MONITOR_MESSAGE_STOP} Recorded file to play for both channels at end of monitoring session

${TXTCIDNAME}           * Result of application TXTCIDName

${VPB_GETDTMF}            chan_vpb

MeetMe会议桥[会议电话桥分器]The MeetMe Conference Bridge

${MEETME_RECORDINGFILE}      Name of file for recording a conference with the "r" option

${MEETME_RECORDINGFORMAT}    Format of file to be recorded

${MEETME_EXIT_CONTEXT}       Context for exit out of meetme meeting

${MEETME_AGI_BACKGROUND}     AGI script for Meetme (DAHDI only)

${MEETMESECS}              * Number of seconds a user participated in a MeetMe conference

${CONF_LIMIT_TIMEOUT_FILE}   File to play when time is up. Used with the L() option.

${CONF_LIMIT_WARNING_FILE}   File to play as warning if 'y' is defined. The default is to say the time remaining.  Used with the L() option.

The VoiceMail() application

${VM_CATEGORY}      Sets voicemail category

${VM_NAME}        * Full name in voicemail

${VM_DUR}         * Voicemail duration

${VM_MSGNUM}      * Number of voicemail message in mailbox

${VM_CALLERID}    * Voicemail Caller ID (Person leaving vm)

${VM_CIDNAME}     * Voicemail Caller ID Name

${VM_CIDNUM}      * Voicemail Caller ID Number

${VM_DATE}        * Voicemail Date

${VM_MESSAGEFILE} * Path to message left by caller

The VMAuthenticate() application

${AUTH_MAILBOX}   * Authenticated mailbox

${AUTH_CONTEXT}   * Authenticated mailbox context

DUNDiLookup()

${DUNDTECH}       * The Technology of the result from a call to DUNDiLookup()

${DUNDDEST}       * The Destination of the result from a call to DUNDiLookup()

chan_dahdi

${ANI2}               * The ANI2 Code provided by the network on the incoming call. (ie, Code 29 identifies call as a Prison/Inmate Call)

${CALLTYPE}           * Type of call (Speech, Digital, etc)

${CALLEDTON}          * Type of number for incoming PRI extension i.e. 0=unknown, 1=international, 2=domestic, 3=net_specific, 4=subscriber, 6=abbreviated, 7=reserved

${CALLINGSUBADDR}     * Called PRI Subaddress

${FAXEXTEN}           * The extension called before being redirected to "fax"

${PRIREDIRECTREASON}  * Reason for redirect, if a call was directed

${SMDI_VM_TYPE}       * When an call is received with an SMDI message, the 'type' of message 'b' or 'u'

chan_sip

${SIPCALLID}         * SIP Call-ID: header verbatim (for logging or CDR matching)

${SIPDOMAIN}         * SIP destination domain of an inbound call (if appropriate)

${SIPUSERAGENT}      * SIP user agent (deprecated)

${SIPURI}            * SIP uri

${SIP_CODEC}           Set the SIP codec for a call

${SIP_URI_OPTIONS}   * additional options to add to the URI for an outgoing call

${RTPAUDIOQOS}         RTCP QoS report for the audio of this call

${RTPVIDEOQOS}         RTCP QoS report for the video of this call

chan_agent

${AGENTMAXLOGINTRIES}  Set the maximum number of failed logins

${AGENTUPDATECDR}      Whether to update the CDR record with Agent channel data

${AGENTGOODBYE}        Sound file to use for "Good Bye" when agent logs out

${AGENTACKCALL}        Whether the agent should acknowledge the incoming call

${AGENTAUTOLOGOFF}     Auto logging off for an agent

${AGENTWRAPUPTIME}     Setting the time for wrapup between incoming calls

${AGENTNUMBER}       * Agent number (username) set at login

${AGENTSTATUS}       * Status of login ( fail | on | off )

${AGENTEXTEN}        * Extension for logged in agent

The Dial() application

${DIALEDPEERNAME}     * Dialed peer name

${DIALEDPEERNUMBER}   * Dialed peer number

${DIALEDTIME}         * Time for the call (seconds). Is only set if call was answered.

${ANSWEREDTIME}       * Time from answer to hangup (seconds)

${DIALSTATUS}         * Status of the call, one of: (CHANUNAVAIL | CONGESTION | BUSY | NOANSWER | ANSWER | CANCEL | DONTCALL | TORTURE)

${DYNAMIC_FEATURES}   * The list of features (from the [applicationmap] section of features.conf) to activate during the call, with feature names separated by '#' characters

${LIMIT_PLAYAUDIO_CALLER}  Soundfile for call limits

${LIMIT_PLAYAUDIO_CALLEE}  Soundfile for call limits

${LIMIT_WARNING_FILE}      Soundfile for call limits

${LIMIT_TIMEOUT_FILE}      Soundfile for call limits

${LIMIT_CONNECT_FILE}      Soundfile for call limits

${OUTBOUND_GROUP}          Default groups for peer channels (as in SetGroup)  * See "show application dial" for more information

The chanisavail() application

${AVAILCHAN}          * the name of the available channel if one was found

${AVAILORIGCHAN}      * the canonical channel name that was used to create the channel

${AVAILSTATUS}        * Status of requested channel

拨号方案宏(Dialplan Macros

${MACRO_EXTEN}        * The calling extensions

${MACRO_CONTEXT}      * The calling context

${MACRO_PRIORITY}     * The calling priority

${MACRO_OFFSET}         Offset to add to priority at return from macro

The ChanSpy() application

${SPYGROUP}           * A ':' (colon) separated list of group names. (To be set on spied on channel and matched against the g(grp) option)

OSP

${OSPINHANDLE}          OSP handle of in_bound call

${OSPINTIMELIMIT}       Duration limit for in_bound call

${OSPOUTHANDLE}         OSP handle of out_bound call

${OSPTECH}              OSP technology

${OSPDEST}              OSP destination

${OSPCALLING}           OSP calling number

${OSPOUTTOKEN}          OSP token to use for out_bound call

${OSPOUTTIMELIMIT}      Duration limit for out_bound call

${OSPRESULTS}           Number of remained destinations


Autohotkey+php实现免浏览器听录音 1199

作者为 发表

AutohotkeyVOIP其他

环境说明:

Elastix 2.5

ln -s /var/spool/asterisk/monitor /var/www/html/


接口文件(php):

<?php
$con=mysql_connect("localhost","root","passwd");
if(!$con) echo "没有连接成功!"; 

mysql_select_db("asteriskcdrdb", $con);
mysql_query("SET NAMES UTF8");
if(isset($_GET["phone"])){
$phone=$_GET["phone"];
if(isset($_GET["date"])){
$calldate=$_GET["date"];
$q = "SELECT * FROM `cdr` WHERE `dst`='$phone' and cast(`calldate` as date)='$calldate' order by `calldate` desc limit 100"; //此处注意dst和src
}else{
$q = "SELECT * FROM `cdr` WHERE `dst`='$phone' order by `calldate` desc limit 100";
}
$result = mysql_query($q, $con); 
if(mysql_num_rows($result)>0){
     while($obj=mysql_fetch_object($result)){
        $obj->src;
        $obj->dst;
        $obj->channel;
        $obj->billsec;
        $obj->calldate;
        $recordingfile = $obj->recordingfile;
        if($recordingfile){
        $a = explode("-",$recordingfile);;
       	$subdir = substr($a[3],0,4)."/".substr($a[3],4,2)."/".substr($a[3],6,2);
		$uri = "/monitor/$subdir/$recordingfile";
		}else{
		$uri='';
		}
		echo $obj->src.",".$obj->dst.",".$obj->channel.",".$obj->dstchannel.",".$obj->disposition.",".$obj->billsec.",".$obj->calldate.",".$uri."\n";
	}
}
}
mysql_free_result($result);

mysql_close($con);
?>


客户端程序(Autohotkey):

FileCreateDir, %A_ScriptDir%\sox
FileCreateDir, c:\temp\
FileInstall, libgomp-1.dll, %A_ScriptDir%\sox\libgomp-1.dll
FileInstall, pthreadgc2.dll, %A_ScriptDir%\sox\pthreadgc2.dll
FileInstall, sox.exe, %A_ScriptDir%\sox\sox.exe
FileInstall, zlib1.dll, %A_ScriptDir%\sox\zlib1.dll


gui, Add, text, x0 y0 w60 h20, 号码
gui, Add, edit, x60 y0 w140 h20 vphone,
Gui, Add, Checkbox, x200 y0 w100 h20 vcd, 呼叫时间
Gui, add, DateTime, x300 y0 w200 h20 vdate,
Gui, Add, Button, x500 y0 w100 h20 Default gsearch, 查询
Gui, Add, Button, x600 y0 w100 h20 glisten, 听取所选
gui, add, ListView, x0 y20 w700 h300, 被叫|主叫|通道|目标通道|状态|通话时长|呼叫时间|录音链接
Gui, Add, ActiveX, x0 w700 h100 vwmp, {6BF52A52-394A-11D3-B153-00C04F79FAA6}
gui, show, , 本地呼叫系统录音听取
GuiControl, , cd, 1
wmp.Settings.Volume := 100

return

search:
Gui, Submit, NoHide
if cd=1
{
	FormatTime, calldate, % date, yyyy-MM-dd
	search_url := "http://192.168.1.2/monitor.php?phone=" phone "&date=" calldate
}
else
	search_url := "http://192.168.1.2/monitor.php?phone=" phone
result := URLDownloadToVar(search_url)
LV_Delete()
loop, Parse, result, `n, `r
{
	obj := StrSplit(A_LoopField,",")
	LV_Add("",obj*)
}
LV_ModifyCol()

return

listen:
FocusedRowNumber := LV_GetNext(0, "F")
if not FocusedRowNumber
{
	MsgBox, 4144, 提示, 您未选择任何一条记录!
	Return
}
LV_GetText(uri, FocusedRowNumber, 8)
if uri
{
	url := "http://192.168.1.2" uri
	if RegExMatch(uri,".*/(.*)\.gsm$",m)
	{
		URLDownloadToFile, % url, % "c:\temp\" m1 ".gsm"
		RunWait, %A_ScriptDir%\sox\sox.exe c:\temp\%m1%.gsm c:\temp\%m1%.wav rate -v, , hide
	}
	else
	{
	RegExMatch(uri,".*/(.*)\.wav$",m)
	URLDownloadToFile, % url, % "c:\temp\" m1 ".wav"
	}
	wmp.Url := "c:\temp\" m1 ".wav"
}
else
	MsgBox, 64, 提示, 录音链接不存在!
return

GuiClose:
ExitApp

获取完整版

# encoding: utf-8
#!/usr/bin/python

import os
import time
import MySQLdb
#设置目录
timearray = time.localtiime(time.time())
timedir = time.strftime("%Y/%m/%d/",timearray)
monitordir = "/var/spool/asterisk/monitor/"+timedir
vi conv.p
# 打开数据库连接
db = MySQLdb.connect("localhost","root","Elastixdb","asteriskcdrdb" )

# 使用cursor()方法获取操作游标 
cursor = db.cursor()

sql = "SELECT recordingfile from cdr where recordingfile like '%.wav';"
try:
   # 执行SQL语句
   cursor.execute(sql)
   # 获取所有记录列表
   results = cursor.fetchall()
   for row in results:
      recordingfile = row[0]
      if os.path.exists(monitordir+recordingfile):
      	  print "转换:%s" % monitordir+recordingfile
      	  os.system("sox "+monitordir+recordingfile+" "+monitordir+recordingfile.replace('wav','gsm'))
      	  os.remove(monitordir+recordingfile.replace('gsm','wav'))
      	  sql = "update cdr set recordingfile=replace(recordingfile,'wav','gsm') where recordingfile='"+recordingfile+"';"
      	  cursor.execute(sql)
      	  db.commit()
      else:
      	  print "找不到文件:%s" % monitordir+recordingfile
except:
   print "Error: unable to fecth data"

# 关闭数据库连接
db.close()


Asterisk队列监控的简单实现 Autohotkey+php+cli 2265

作者为 发表

AutohotkeyVOIP

首先你得有个获取队列情况的接口。如果使用ami的话太麻烦,接收的数据控制不好断节,所以我用了php+shell的形式获取数据。由于是局域网内使用,所以没加验证,有需求的自己加一下。

vi /var/www/html/cli.php

按i进入插入模式,粘贴上如下代码:

<?php
if(isset($_GET["cmd"])){ //先判断是否是预期参数
$fp=popen("asterisk -x \"".$_GET["cmd"]."\"","r"); //asterisk -x单句命令执行
while(!feof($fp))
echo fgets($fp,4096);
pclose($fp);
}
?>

按Esc输入":wq"保存退出。好了这个接口就可以使用来执行Asterisk CLI命令了。


然后通过你自己的坐席数据库接口,结合ahk写一个客户端。

;数据库配置信息
host = 135.230.71.1
api = http://%host%/sqlapi.php
#MaxMem 1024
;检查连通性
if Not InStr(ping_info := ping(host),"正常")
	{
	MsgBox, 4112, 网络错误, % ping_info
	ExitApp
	}
;创建GUI
gui, add, edit, x0 y0 w800 h400 vshow,
gui, show, , 本地呼叫系统坐席队列监控
gui, +AlwaysOnTop +Resize
;循环监控坐席状态 3秒间隔
Loop
{
out =
Queue := QueueStatus() ;获取队列状态数组
tp := get_result_obj("select 队列,业务 from [我是口令呼叫系统数据库].[dbo].[呼叫系统业务分派] where 状态=1 and ((cast(getdate() as time) between 开始时间1 and 结束时间1) or (cast(getdate() as time) between 开始时间2 and 结束时间2));") ;这是一个获取当前正在执行的任务的语句
task := []
for k,v in tp
	task[v[1]] := v[2]
tp := get_result_obj("select 分机,工号,姓名 from [我是口令呼叫系统数据库].[dbo].[呼叫系统分机信息] where [工号] is not null") ;获取已经登记的坐席信息
user := []
for k,v in tp
	user[v[1]] := {"id":v[2],"name":v[3]}
;格式化输出
for group,gv in Queue
{
	out .= task[group] "(" group ") 策略:" gv["strategy"] " " gv["incall"] "个等待来电 平均摘机时间:" gv["holdtime"] "(秒)平均通话时长:" gv["talktime"] "(秒)`n"
	for exten,mv in gv["member"]
	{
		sp =
		loop % 20-strlen(user[exten]["name"])
			sp .= " "
		;很笨的一种汉化替换方法
		status := RegExReplace(mv["status"],"In use","通话中")
		status := RegExReplace(status,"Not in use","空闲")
		status := RegExReplace(status,"Ringing","振铃")
		status := RegExReplace(status,"Unavailable","不可用")
		status := RegExReplace(status,"On hold","保持")
		out .= "	坐席:" user[exten]["name"] "(" user[exten]["id"] " " exten ")" sp " 类型:" mv["kind"] " 状态:"  status " 本次签入后呼叫量:" mv["callcount"] " 最后一次摘机:" mv["lastcalltime"] "秒前`n"
	}
	for k,cv in gv["caller"]
		out .= "	来电:" k "." cv["phone"] " 等待时间:" cv["wait"] "秒`n"
	out .= "`n"

}
GuiControl, , show, % out
Sleep, 3000
}
Return

;界面调整尺寸
GuiSize:
GuiControl, move, show, % "w" A_GuiWidth "h" A_GuiHeight
Return

;获取状态函数
QueueStatus(){
src := URLDownloadToVar("http://135.230.71.2/cli.php?cmd=queue show") ;你的Asterisk的cli接口
queues := []
Loop, Parse, src, `n, `r
{
	line := A_LoopField
	if RegExMatch(line,"(\d+) has (\d+) calls \(max unlimited\) in '(\w+)' strategy \((\d+)s holdtime, (\d+)s talktime\), W:\d+, C:\d+, A:\d+, SL:[0-9\.]+% within \d+s",qtm) ;队列标题匹配
	{
		cqueue := qtm1
		queues[cqueue] := {"incall":qtm2,"strategy":qtm3,"holdtime":qtm4,"talktime":qtm5,member:{},caller:{}}
	}
	else if RegExMatch(line,"\s+sip/(\d+) with penalty 1 \(ringinuse disabled\) \((\w+)\) \((.+)\) has taken (\d+) calls \(last was (\d+) secs ago\)",mcm) ;坐席匹配1
		queues[cqueue]["member"][mcm1] := {"kind":mcm2,"status":mcm3,"callcount":mcm4,"lastcalltime":mcm5}
	else if RegExMatch(line,"\s+sip/(\d+) with penalty 1 \(ringinuse disabled\) \((\w+)\) \((.+)\) has taken no calls yet",mcm) ;坐席匹配2
		queues[cqueue]["member"][mcm1] := {"kind":mcm2,"status":mcm3,"callcount":0,"lastcalltime":"NULL"}
	else if RegExMatch(line,"\s+(\d+). DAHDI/i1/(\d+)-\w+ \(wait: 0:(\d+), prio: 0\)",ccm) ;来电匹配
		queues[cqueue]["caller"][ccm1] := {"phone":ccm2,"wait":ccm3}
}
Return queues
}

;返回csv带标题格式查询结果
get_result_with_colname(sql){
global api
result := URLDownloadToVar(api "?str=" urlencode(sql "我是口令") "&o=1","UTF-8")
return RegExReplace(result,"`n$","")
}

;返回csv查询结果
get_result(sql){
global api
result := URLDownloadToVar(api "?str=" urlencode(sql "我是口令"),"UTF-8")
return RegExReplace(result,"`n$","")
}

;返回查询数组
get_result_obj(sql){
global api
result := URLDownloadToVar(api "?str=" urlencode(sql "我是口令"),"UTF-8")
;return RegExReplace(result,"`n$","")
line := strsplit(result,"`n","`r")
for k,v in line
{
	if v
		line[k] := strsplit(v,",")
	Else
		line.remove(k)
}
return line
}

;返回1行数据
get_1_result(sql){
global api
result := URLDownloadToVar(api "?str=" urlencode(sql "我是口令"),"UTF-8")
return RegExReplace(result,"^([^\n]*)\n.*$","$1")
}

;返回执行影响结果
get_rowcount(sql){
global api
result := URLDownloadToVar(api "?str=" urlencode(sql "我是口令") "&o=2","UTF-8")
return RegExReplace(result,"^([^\n]*)\n.*$","$1")
}

URLDownloadToVar(url, Encoding = "",Method="GET",postData=""){ ;网址,编码,请求方式,post数据
	hObject:=ComObjCreate("WinHttp.WinHttpRequest.5.1")
	if Method = GET
	{
		Try
		{
			hObject.Open("GET",url)
			hObject.Send()
		}
		catch e
			return -1
	}
	else if Method = POST
	{
		Try
		{
			hObject.Open("POST",url,False)
			hObject.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
			hObject.Send(postData)
		}
		catch e
			return -1
	}

	if (Encoding && hObject.ResponseBody)
	{
		oADO := ComObjCreate("adodb.stream")
		oADO.Type := 1
		oADO.Mode := 3
		oADO.Open()
		oADO.Write(hObject.ResponseBody)
		oADO.Position := 0
		oADO.Type := 2
		oADO.Charset := Encoding
		return oADO.ReadText(), oADO.Close()
	}
	return hObject.ResponseText
}



Ansi2UTF8(sString)
{
   Ansi2Unicode(sString, wString, 0)
   Unicode2Ansi(wString, zString, 65001)
   Return zString
}
UTF82Ansi(zString)
{
   Ansi2Unicode(zString, wString, 65001)
   Unicode2Ansi(wString, sString, 0)
   Return sString
}
Ansi2Unicode(ByRef sString, ByRef wString, CP = 0)
{
     nSize := DllCall("MultiByteToWideChar"
      , "Uint", CP
      , "Uint", 0
      , "Uint", &sString
      , "int", -1
      , "Uint", 0
      , "int", 0)
   VarSetCapacity(wString, nSize * 2)
   DllCall("MultiByteToWideChar"
      , "Uint", CP
      , "Uint", 0
      , "Uint", &sString
      , "int", -1
      , "Uint", &wString
      , "int", nSize)
}
Unicode2Ansi(ByRef wString, ByRef sString, CP = 0)
{
     nSize := DllCall("WideCharToMultiByte"
      , "Uint", CP
      , "Uint", 0
      , "Uint", &wString
      , "int", -1
      , "Uint", 0
      , "int", 0
      , "Uint", 0
      , "Uint", 0)
   VarSetCapacity(sString, nSize)
   DllCall("WideCharToMultiByte"
      , "Uint", CP
      , "Uint", 0
      , "Uint", &wString
      , "int", -1
      , "str", sString
      , "int", nSize
      , "Uint", 0
      , "Uint", 0)
}

urlencode(string){
string := Ansi2UTF8(string)
StringLen, len, string
Loop % len
{
SetFormat, IntegerFast, hex
StringMid, out, string, %A_Index%, 1
hex := Asc(out)
hex2 := hex
StringReplace, hex, hex, 0x, , All
SetFormat, IntegerFast, d
hex2 := hex2
If (hex2==33 || (hex2>=39 && hex2 <=42) || hex2==45 || hex2 ==46 || (hex2>=48 && hex2<=57) || (hex2>=65 && hex2<=90) || hex2==95 || (hex2>=97 && hex2<=122) || hex2==126)
	content .= out
Else
	content .= "`%" hex
}
Return content
}


ping(ip){
FileEncoding,
RunWait, %ComSpec% /c ping -n 1 %ip% >%A_Temp%\ahk_ping.tmp, , Hide
FileRead, content, %A_Temp%\ahk_ping.tmp
StringReplace, content, content, `r, , All
StringSplit, var, content, `n
If content Contains 请求超时,Request timed out
	Return "请求超时"
If content Contains 找不到主机,could not find host
	Return "找不到主机 "
If content Contains 无法访问目标主机,Destination host unreachable
	Return "无法访问目标主机 "
Else
	{
	time := RegExReplace(var3, "(来自|Reply from) \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}[\s的回复|]*: (字节|bytes)=\d{1,3}\ (时间|time)[=<](\d{1,3})ms TTL=\d{1,3}","$4")
	Return "正常 time:" time "ms"
	}
FileEncoding, UTF-8
}

;调试用 输出数组
show_obj(obj,menu_name:=""){
static id
if menu_name =
    {
    main = 1
    id++
    menu_name := id
    }
Menu, % menu_name, add,
Menu, % menu_name, DeleteAll
for k,v in obj
{
if (IsObject(v))
	{
    id++
    submenu_name := id
    Menu, % submenu_name, add,
    Menu, % submenu_name, DeleteAll
	Menu, % menu_name, add, % k ? "【" k "】[obj]" : "", :%submenu_name%
    show_obj(v,submenu_name)
	}
Else
	{
	Menu, % menu_name, add, % k ? "【" k "】" v: "", MenuHandler
	}
}
if main = 1
    menu,% menu_name, show

MenuHandler:
return
}

GuiClose:
ExitApp

好了,看下效果:


Centos6安装STUN服务器 5053

作者为 发表

LinuxVOIP

虽然免费的stun服务器也能凑合着用,但是也越来越不适用于中国的网络环境,所以你可以到大的IDC去买云主机并购买额外IP来搭建STUN服务器,主流成本100多RMB一个月。

首先你的有两个公网IP的服务器!然后注意把防火墙关掉。

#下载stun

wget http://ncu.dl.sourceforge.net/project/stun/stun/0.97/stund-0.97.tgz

#检查安装编译环境

yum -y install gcc automake autoconf libtool make

#解压

tar -zxvf stund-0.97.tgz

#进入目录

cd stund

#编译

make

#复制服务端

mkdir /root/bin/
cp server /root/bin/stunserver

#创建服务脚本

vi /etc/init.d/stund

#然后填充服务脚本

#!/bin/bash
# 
#chkconfig: 2345 70 30
#description:STUN Server
RETVAL=0 
start(){ #启动服务的入口函数  
echo  "STUN Server is started..."  
/root/bin/stunserver -v -h 8.8.8.8  -a 4.4.4.4 -v
#主IP 辅助IP
}  
  
stop(){ #关闭服务的入口函数  
echo  "STUN Server is stoped..."  
}  
  
#使用case选择  
case $1 in  
start)  
start  
;;  
stop)  
stop  
;;  
*)  
echo "error choice ! please input start or stop";;  
esac  
exit $RETVA

#按【ESC】输入:wq保存退出

#设置权限

chmod +x /etc/init.d/stund

#添加服务

chkconfig --add stund

#设置防火墙

setup

#找到Firewall设置 把Enable去掉,然后Save保存退出

#为了安全 可以修改root用户名和设置denyhosts

#重启后,你就可以下载NatTypeTester测试你的服务器了。

asterisk语音编码问题g729和g723的添加 6818

作者为 发表

VOIP

关于asterisk没有G729G723编码的问题

1、 因为在安装asterisk的时候是没有对应的codec_g729.socodec_g723.so模块的。

想要查看自己的asterisk有什么模块,可以进入asterisk控制台:

默认没有可用模块的情况:

 

 

 

添加可用G729G723模块以后的情况:

 

下面讲述如何添加可用模块:

全过程请参照以下网页配置:

http://wiki.kolmisoft.com/index.php/G723/G729_Codec_installation#Testing

下载对应模块地址:

http://asterisk.hosting.lv/

请根据自己服务器的配置和环境选择对应的模块下载。

 

 

 

 

 

1、需要修改对应的confi文件:/etc/asterisk/codecs.conf下添加

[g723]

; 6.3Kbps stream, default

sendrate=63

; 5.3Kbps

;sendrate=53

2、 sip.conf或者iax.conf中全局下添加:a

disallow=all

allow=g729

allow=g723

 

操作上需要进行如下操作:

1、 下载对应硬件和软件编译环境的G729G723语音模块。

2、 上传到服务器对应的文件夹/usr/lib/asterisk/modules/

3、 改名对应的模块,对应的名字为codec_g729.socodec_g723.so

4、 给两个对应的模块赋予权限:chmod 777 codec_g729.so chmod 777 codec_g723.so

5、 asterisk的控制台上使用命令加载刚才添加的两个模块:module load codec_g729.so

module load codec_g723.so.

 

 

然后手动加载模块:

 

 

 

 

 

 

 

 

加载之后,查看看是否支持此模块:

 

 

使用命令查看是否有此模块:

 

 

至此,添加成功可以使用g729g723编码进行通讯了。

 


  • 1 • 2
  • 1
  • 2

友情链接:Autohotkey中文论坛Autohotkey中文帮助Autohotkey官网我的B站直播间如若生涯一场梦博客联系作者免GooglePlay APK下载

 主题设计 • skyfrit.com  Thinkai's Blog | 保留所有权利

50 queries in 1.460 seconds |