Yate教程1

From:http://yate.null.ro/pmwiki/index.php?n=Main.CppTutorial1

Yate可分为两个部分     * Yate内核     * Yate模块     *Yate内核提供基础,辅助API以及消息系统     *Yate模块使用Yate内核实现特定的功能 Yate模块的类型 Yate模块可分为一下几种     1.通道     2.路由器     3.电话历史记录(Call Detail Recorder)     4.计费程序     5.其他模块 如何指定模块的类型 模块类型在这里涉及许多概念性的东西。Yate的设计中并不区分模块的种类,而是根据模块处理的消息类型来区分模块类型。例如一个通道模块接受call.execute消息,并创建一个通道来接受处理它。有此特征的模块我们称之通道模块。另一方面即使如果模块可能接受call.execute消息并处理一个事情,但并不创建一个通道/终端,则它不是一个通道模块。CDRBuilder就是这样的模块。如果你还不清楚,稍等,接下来的例子会说明清楚。

程序员眼里的消息   消息应正确派发到注册了并在监听该消息的模块中。模块可以指定接受消息的优先级。如果一模块监听的call.execute消息优先级为50,其他模块也在监听call.execute消息,但优先级值大于50,则该模块应该先于其他模块获取call.execute消息。一旦接收到该消息,模块可向派发器返回true或fale,并附带一些额外信息。如果返回true,则派发器停止向后续的模块发送消息。返回false,则允许消息按照优先级继续派发到其他模块中。 

  Yate消息不会同Windows消息相混淆,因为他只在Yate系统范围内发送而没有使用操作系统机制发送消息。此外,Yate消息构造是以字符串定义的,而OS消息使用的是数值。 TelEngine命名空间     所有的Yate API都什么在TelEngine命名空间中,命名空间是C++的一个概念,用于减少程序中变量名和函数名重名冲突。因此,要使 用命名空间TelEngine,如不想写TelEngine::blahblah,你可以使用:

using namespace TelEngine;

我们的第一个模块   我们现在开始写我们的第一个模块,可以接受call.execute消息,并将其呼叫和被叫的号码输出到控制台中。我们设模块名为mymodule1.ln。在这个模块中我们需要讨论以下几个类。     *Module     *Message     *MessageReceiver     *String 同样还得介绍call.route

CPP文件准备 我们需在模块目录下创建一个名为mymodule1.cpp的文件 包含telengine.h文件则可使用YATE的API 第一步--模块代码 和前面解释的一样,Yate模块要申明他是一个Yate模块都需从Module类派生。Module是从多个类派生的。在Yate API继承关系如下:

class YATE_API Module : public Plugin, public Mutex, public MessageReceiver, public DebugEnabler 
...

注意Plugin类向Yate提供了加载模块的功能 在我们的模块中声明类如下:

class MyModule : public Module  
{  
public:  
    MyModule()  
        : Module("MyModule1","misc"), m_init(false) {}  
 virtual void initialize();  
 virtual bool received(Message &msg,int id);  
private:  
 enum 
    {  
        CallRoute = Private + 1  
    } PrivateRelayID;  
 bool m_init;  
}; 

第二步:创建Module类的静态变量 当Yate模块加载一个模块是,他首先会在模块中(Plugin)查找名为_plugin的静态变量。在我们的例子中,我们需要定义类MyModule(派生于Plugin)的一个静态变量。Yate提供了帮助做这个,仅需要这样使用:

INIT_PLUGIN(MyModule);

第三步:模块initialize()的重要性 你需特别注意到我们在MyModule声明定义的initialize方法。initialize函数在Plugin类是虚函数,在Yate加载模块时会被调用。MyModule需要重载它,做一些模块初始化工作。通常在这里注册模块想监听的消息。我们可这样写代码:

void MyModule::initialize()  
{  
    Output("Initializing module mymodule1");  
 if(!m_init) {  
    m_init = true;  
    }  
}  

Yate提供的Output函数输出信息到控制台。它只在必要的时候使用。Yate同样提供了一些其他API函数将调试信息输出到控制台。 第四步:添加代码接受消息 模块通常需要接受一个或多个消息。模块接受到一个消息并执行程序制度的工作。Module类派生与MessageReceiver,MessageReceiver通过虚函数received()提供了接受消息能力。我们可按自己爱好添加代码接受消息,像这样:

void MyModule::initialize()  
{  
    Output("Initializing Module mymodule1");  
 if(!m_init) {  
    Engine::install(new MessageRelay("call.route",this,CallRoute,55));  
    m_init = true;  
    }  
}  

Yate中的类Engine。Yate创建了一个Engine的静态对象作为他(Yate)的启动(不是模块的启动)。这个类启动真个Yate的服务器/服务。这个类全是静态成员函数。Install()同样是静态函数,这也就是我们为什么Engine::install这样调用的原因。install向yate提供了我们的MessageRelay类对象,指定了我们想要监听消息的消息id、监听优先级等。第三个参数CallRoute是枚举值,它仅指定我们想关联消息的消息ID。枚举值CallRoute为Private+1,在类Module中定义,用于指定(说明)该消息在模块中没有任何RelayID。可看看Yate中Module类的枚举值。当你监听到多个消息,你需要识别监听到的消息,当然这有多种方式实现。注意在MessageRelay的最好一个参数值为55,这说明我们想监听的消息优先级别值为55。因此如果其他模块也在监听同样的消息且优先级更高,将先接收到这个消息并且如果他返回非ture,我们的这个模块才能接受到这个消息。MessageRelay被Yate用例发送消息,它的构造函数拥有一个MessageReceiver类的对象用户消息的通知。我们MyModule继承于Module,而Module继承于MessageReceiver,因此,我们在MyModule可提供这个对象(MessageReceiver)。 第五步:重载received 类MessageReceiver的received(Message &msg,int id)方法由Yate调用,用于派发注册过监听的消息。received在MessageReceiver中声明为虚函数。注意,返回值为bool,如果处理完这个消息,并不想后面的模块接受处理该消息,返回true。希望后续的模块继续处理该消息返回false即可。这里(received)我们可以添加自己的逻辑代码。在received中我们可写一些代码,在call.route消息来临时,输出呼叫者和被呼叫者名。

bool MyModule::received(Message &msg,int id)  
{  
    String called,caller;  
    called = msg.getValue("called");  
    caller = msg.getValue("caller");  
    Output("mymodule1: call.route called  
    caller %s, and called %s",caller.c_str(),called.c_str());  
 return false;  
}  

上述代码使用了Yate API提供的String类。从名可知这个类提供了字符串的相关操作。Message继承与NamedList,这是YATE提供的另一个类,用于更好管理字符串与字符串直接的映射链表。类NamedList的函数getValue(),我们先获取被叫号码(熟知的DNID),然后获取呼叫者的号码,作为电信运营商的ANI/CLI(被叫者ID/呼叫者ID)。c_str为String的成员函数,返回字符串存储的数据,类型为const char*.

#include <yatengine.h> 
#include <yatephone.h> 
#include <stdio.h> 
#include <stdlib.h> 
using namespace TelEngine;  
class MyModule : public Module  
{  
public:  
    MyModule()  
        : Module("MyModule1","misc"), m_init(false) {}  
 virtual void initialize();  
 virtual bool received(Message &msg,int id);  
private:  
 enum 
    {  
        CallRoute = Private + 1  
    } PrivateRelayID;  
 bool m_init;  
};  
bool MyModule::received(Message &msg,int id)  
{  
    String called,caller;  
    called = msg.getValue("called");  
    caller = msg.getValue("caller");  
    Output("mymodule1: call.route called  
    caller %s, and called %s",caller.c_str(),called.c_str());  
 return false;  
}  
void MyModule::initialize()  
{  
    Output("Initializing Module mymodule1");  
 if(!m_init) {  
        Engine::install(new MessageRelay("call.route",this,CallRoute,55));  
        m_init = true;  
    }  
}  
INIT_PLUGIN(MyModule);  
/* vi: set ts=8 sw=4 sts=4 noet: */ 

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏哲学驱动设计

OEA ORM 框架中的冗余属性设计

OEA 框架提供了多种方式来优化分布式数据查询的性能,本篇将会说明如何以声明 OEA 冗余属性的方式,来实现轻量级的数据冗余,以减少关联查询次数及网络数据传输量...

2439
来自专栏Vamei实验室

Linux从程序到进程

计算机如何执行进程呢?这是计算机运行的核心问题。即使已经编写好程序,但程序是死的。只有活的进程才能产出。我们已经从Linux进程基础中了解了进程。现在我们看一下...

2239
来自专栏欧阳大哥的轮子

深入iOS系统底层之CPU寄存器介绍

计算机是一种数据处理设备,它由CPU和内存以及外部设备组成。CPU负责数据处理,内存负责存储,外部设备负责数据的输入和输出,它们之间通过总线连接在一起。CPU内...

1883
来自专栏前端桃园

ES6之路之模块详解

1353
来自专栏安恒网络空间安全讲武堂

writeup | 强网杯—Simple check

Simplecheck 下载之后使用winhex打开文件 ? 发现是属于android的逆向题目 修改后缀为.apk 先使用模拟器安装打开该apk ? 猜测题目...

3835
来自专栏自动化测试实战

flask第十篇——url_for【3】

2406
来自专栏企鹅号快讯

一文学会Python协程

Python圣诞学习狂欢夜 距离开始还有3天 . . . 详情 . . . 生成器和协程的介绍 生成器(Generator)的本质和特点 生成器 是 可以生成一...

30210
来自专栏编程

java编程思想之并发

编程问题中的相当一大部分都可以通过顺序编程来解决。然而,对于某些问题,如果能够并行的执行程序中的多个部分,则会变得非常方便甚至非常必要,这些部分要么可以并发执行...

2127
来自专栏软件开发 -- 分享 互助 成长

注意map<> 的[]

其实在之前一篇关于map的基本操作中已经提到过注意[]操作,这里再强调一下。 先看下面的程序: #include<iostream> #include<map>...

1756
来自专栏程序员的碎碎念

php写接口入门

了解JSON JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation) JSON 是轻量级的文本数据交换格式 ...

1.7K8

扫码关注云+社区

领取腾讯云代金券