使用 esl 的c++ 来进行拨号计划的控制,有几个细节,困扰了我好几天。这些都是使用lua脚本所没有碰到的。
这里有说明。
主要是这句
async 表示异步执行
full 表示所有的内置程序都可用。必须要要这个
举例
1, t_pEslConn->execute("playback", "/usr/local/freeswitch/sounds/tone_callout/CallOut1.wav");
2, t_pEslConn->execute("hangup");
3, t_pEslConn->execute("playback", "/usr/local/freeswitch/sounds/tone_callout/CallOut2.wav");
如果是async模式,这3句都会走。
如果是在正常运行的模式下,根本听不到声音,就挂断了。
如果在第二行第三行打上断点,当走到第二行的时候(第二行还没运行),可以听到第一行运行的音乐;再走一步,音乐中断电话挂断;再走一步,没效果了(因为电话已经挂断了)。
如果是 同步模式。playback是阻塞运行的,只能在第一行运行完之后才能走到第二行。
(这种方式有点麻烦,可以直接看下一条)
生成freeswitch事件的几种方式
c++ esl 创建ESLevent sendMSG
ESLconnection* t_pEslConn = 、、、;
ESLevent *t_willSendEvent = new ESLevent("CUSTOM","calltest1::calltest1_sub");
t_willSendEvent->addHeader("call-command","execute");
t_willSendEvent->addHeader("execute-app-name","playback");
t_willSendEvent->addHeader("execute-app-arg","/usr/local/freeswitch/sounds/tone_callout/CallOut1.wav");
t_willSendEvent->addHeader("event-lock", "true");
const char* t_cWillSendSerial = t_willSendEvent->serialize();//这一步是为了看构造的对不对
int t_iMsgRtn = t_pEslConn->sendMSG(t_willSendEvent);
t_pEslConn->setEventLock("1"); //这一句保证那些异步运行的程序能按顺序执行
里面调用了一个函数
int ESLconnection::setEventLock(const char *val)
{
if (val) {
handle.event_lock = esl_true(val);
}
return handle.event_lock;
}
//下面这个函数看起来很有道理
static __inline__ int esl_true(const char *expr) {
return (expr && (!strcasecmp(expr, "yes")
|| !strcasecmp(expr, "on")
|| !strcasecmp(expr, "true")
|| !strcasecmp(expr, "enabled")
|| !strcasecmp(expr, "active")
|| !strcasecmp(expr, "allow")
|| atoi(expr)));
}
再拿这三行来说
1, t_pEslConn->execute("playback", "/usr/local/freeswitch/sounds/tone_callout/CallOut1.wav");
2, t_pEslConn->execute("hangup");
3, t_pEslConn->execute("playback", "/usr/local/freeswitch/sounds/tone_callout/CallOut2.wav");
设置 async full 之后。
正常运行的时候,三行会直接走下去,但是实际运行的时候,会先播放完第一行的音乐,然后再走第二行挂断。
这样就达到了lua脚本的效果。
string t_args;
t_args += t_pALegUuid;
t_args += " ";
t_args += t_pBLegUuid;
const char * t_cArgs = t_args.c_str();
ESLevent* t_call_event2 = t_pEslConn->bgapi("uuid_bridge", t_cArgs);
uuid_bridge 这个api属相有点特别,如果是在同步模式下,根本对接不起来。但是esl程序杀死后,a腿与b腿却又连起来了。貌似是里面有个程序在运行。
因此只能使用异步模式。
也就是使用esl的c++接口,通过底层代码可知,里面实际上封装的是esl的c接口。
但是这个面向对象使用起来很操蛋。
ESLconnection 这个对象的接口的返回值是ESLevent,你要自己去管理它的内存释放。
我一般写成下面这个样子
auto t_rtn = make_shared(t_pESLConn->execute("playback", audioPath.c_str()));
//或者
ESLevent* t_pEslInfo = t_pEslConn->getInfo();
shared_ptr t_spEslInfo(t_pEslInfo);//为了能自动释放内存
我翻看了源码,确实要我们自己手动管理这个返回值的释放。