




已阅读5页,还剩41页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
pwlib是一套跨平台的C+的开发库,使基于pwlib上开发的应用能够很少量的移植就可以跑在windows和unix的平台上. Open323是澳洲的一家公司驱动的open source的h323协议族实现, 还不够十分的完整, 但是已经是非常的难得了. 在windows上和linux下都能编译使用, 我已经试过了. Windows上编译他们比较麻烦, 注意的是一定要用batch building. 在VC7上编译openh323的动态连接库的时候, VS.net会崩溃, 注意避开, 不过也可以试试看看现象, 如果能够解决, 请告诉我一下. 在linux上编译就没有什么好说的了, 设好两个环境变量(PWLIBDIR, OPENH323DIR), 就可以在展开的目录下编译了, 先编译PWLIB, 再编译OPENH323, 别忘了将相应xx/lib写到/etc/ld.so.conf下. 我这里可能对安装讲的不够详细, openh323讲的非常详细, 大家可以去看. 以linux平台为例: 使用pwlib, 在成功编译之后, 到$(PWLIBDIR)/SAMPLES/ 这里是一些例子, hello_world 是个非常简单的工程, 从这里我们可以看到如何写使用pwlib的Makefile: # Simple makefile for the hello world program PROG = hello SOURCES = hello.cxx ifndef PWLIBDIR PWLIBDIR=$(HOME)/pwlib endif include $(PWLIBDIR)/make/ptlib.mak 关键是包含了一个ptlib.mak hello.cxx #include class Hello : public PProcess PCLASSINFO(Hello, PProcess) public: void Main(); ; PCREATE_PROCESS(Hello) void Hello:Main() cout Hello world!n; 非常有代表性. Include $(PWLIBDIR)/make/ptlib.mak 这样就可以make all, make debug的之类的进行编译, 需要的头文件库都会替你安排好. 编译的结果就会放在obj_linux_x86_xx, xx 表示你用的是debug编译还是其他, 如果是debug, xx就是d. 使用pwlib的程序, 必然要有一个PProcess的子类, 作为整个进程, 这是指在console模式下, gui模式的用PApplication这个我没有用过. Pwlib里面的类大多都是P开头, (可能是取其兼容的意思, 跨平台的特性, 我瞎猜的), 在进程中如果想创建新的线程就创建PThread子类的对象, 对于这种关于过程的类,都有Main函数等待子类去实现. 在使用所有的P类的时候, 注意使用两个宏, 声明类的时候PCLASSINFO(Hello, PProcess); 分号可以加, 也可不加. PProcess的子类的实现的时候要用PCREATE_PROCESS(Hello);,这个东西把main()之类的系统入口封装了, 由他来调用Main()成员函数. 在使用线程的时候, 如果想让线程从线程的对象一创建就运行, 就应该在PThread子类中的构造函数中调用父类的Resume(). 关于pwlib先说这些, 在使用Openh323的时候到处都会用到pwlib的东西和概念. Openh323: 终于进入正题了, 先粗略的讲点概念(多余了), H323是指协议族了, 包含了很多规范, 它来自ITU, 应会议的需要而产生, 信令相关的东西用H225 H245,类似Q931,用ASN1编码后在tcp之上传输, 数据相关的就是编码解码的东西了(包括音频视频), 音频g711(alaw, ulaw)了等等多了, 视频h261, 好像h263还没实现. 在H323的系统里进行通讯的角色实体就是Endpoint, 每个Endpoint可以有很多的Connection, 每个Endpoint也可以拥有很多的逻辑角色, 这个不讨论. Endpoint 在Openh323中就是类H323Endpoint的实例 Connection 在Openh323中就是 H323Connection的实例 当Endpoint接收了一个远程的连接请求, Endpoint就会创建一个H323Connection; 当Endpoint发出一个连接的请求, Endpoint也会创建一个H323Connection Connection 就会进入一个状态机, 在各个状态中, Connetcion会相应的执行相应的方法,这些方法, 大多都是Onxxxxx(), 是虚函数, 我们可以自己通过继承H323Connection创建其子类, 并且在我们想做事的时机去重载相应的虚函数. 这是使用Openh323的一个基本的思路. 现在我们可以看看如何写一个自己H323的Endpoint, 让它能够和netmeeting互操作.成功编译Openh323后在它的samples的目录下面有几个例子, mfc是指在windows下如何使用MFC和Openh323一起开发, 还有simple, 这是个简单的H323的Endpoint的实现, 作为理解OpenH323的库如何使用和开发的技巧方法已经足够了. 程序运行主线: PWLIB(PCREATE_PROCESS(SimpleH323Process)-SimpleH323Process: SimpleH323Process()-SimpleH323Process:Main(); Main()如果结束, 这个程序就结束了, 可是Main()里面有个死循环, 写过图形程序的朋友们都知道, 这就是在等消息来呀. 在VC中称之为Interface thread. 程序注解: main.h 这个文件包含了程序用到的所有类的声明, 一般应该至少有三个类: 来自PProcess的一个主进程的, 或者说作为界面线程的;(只有一个对象) 来自H323Endpoint的, 标识这个H323端点的;(只有一个对象) 来自H323Connection的, 标识所有和这个H323端点相关的连接;(可以有多个) #ifndef _SimpleH323_MAIN_H #define _SimpleH323_MAIN_H /避免头文件重复包含 #include class SimpleH323EndPoint : public H323EndPoint /使用Pwlib的要求, 就像使用MFC, 有n多的宏, 可以看看pwlib的源码, /宏展开都干了什么 PCLASSINFO(SimpleH323EndPoint, H323EndPoint); public: SimpleH323EndPoint(); SimpleH323EndPoint(); / overrides from H323EndPoint / 重载H323EndPoint的函数 / 当收到一个远程的呼入和发出呼出的请求的时候 virtual H323Connection * CreateConnection(unsigned callReference); / 有远程的请求来到, 这是在CreateConnection之后的 virtual BOOL OnIncomingCall(H323Connection &, const H323SignalPDU &, H323SignalPDU &); /应答远程的呼入 virtual H323Connection:AnswerCallResponse OnAnswerCall(H323Connection &, const PString &, const H323SignalPDU &, H323SignalPDU &); /当连接被Forward virtual BOOL OnConnectionForwarded(H323Connection &, const PString &, const H323SignalPDU &); /当连接建立 virtual void OnConnectionEstablished(H323Connection & connection, const PString & token); /当连接撤销 virtual void OnConnectionCleared(H323Connection & connection, const PString & clearedCallToken); /当连接需要打开声音的通道 virtual BOOL OpenAudioChannel(H323Connection &, BOOL, unsigned, H323AudioCodec&); / New functions / 自己添加的新函数, 父类中不存在 BOOL Initialise(PArgList &); BOOL SetSoundDevice(PArgList &, const char *, PSoundChannel:Directions); / 每个连接会有一个Token来唯一标识 PString currentCallToken; protected: BOOL autoAnswer; PString busyForwardParty; ; class SimpleH323Connection : public H323Connection PCLASSINFO(SimpleH323Connection, H323Connection); public: /创建连接对象的时候将Endpoint的对象以引用传进来 /引用的概念就是将整个对象暴露给你的意思, 不是复制了一份的意思, /对象还是原来的对象, 所以在Connection中修改了EndPoint的某些属性后 /就是在操作着传进来的对象, 这是C+的基本概念, OpenH323大量的使用 /引用传递对象, 对引用的概念要理解 SimpleH323Connection(SimpleH323EndPoint &, unsigned); /重载了两个父类的函数 / 当打开逻辑通道的时候(等于没说) virtual BOOL OnStartLogicalChannel(H323Channel &); / 处理用户输入, 这个不是之运行这个程序的用户,而是这个连接上的用户输入 / 一般应该是拨号了之类的, virtual void OnUserInputString(const PString &); protected: / 快速连接? BOOL noFastStart; ; class SimpleH323Process : public PProcess /主进程, 类似VC的用户界面线程, /他是整个程序的入口点, 和结束点 /创建了EndPoint对象后会有好几个线程启动 /这个就是主线程 PCLASSINFO(SimpleH323Process, PProcess) public: SimpleH323Process(); SimpleH323Process(); /这个函数会被自动调用, 是我们程序的入口了 void Main(); protected: /这个H323端点对象 SimpleH323EndPoint * endpoint; ; #endif / _SimpleH323_MAIN_H 下面是main.cpp 所有的类的实现了 #include #ifdef _GNUC_ #define H323_STATIC_LIB #endif #include main.h #include ././version.h #define new PNEW / 这个东西里边可能封装了标准的main函数 PCREATE_PROCESS(SimpleH323Process); / /几个宏都在version.h里面定义 SimpleH323Process:SimpleH323Process() : PProcess(OpenH323 Project, SimpleH323, MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER) endpoint = NULL; SimpleH323Process:SimpleH323Process() delete endpoint; void SimpleH323Process:Main() cout GetName() Version GetVersion(TRUE) by GetManufacturer() on GetOSClass() GetOSName() ( GetOSVersion() - GetOSHardware() Initialise(args) return; /看看命令行里是不是想直接呼叫另一个H323的endpoint.有没有l(listen)的option /如果是就MakeCall, / See if making a call or just listening. if (args.HasOption(l) cout Waiting for incoming calls for GetLocalUserName() n; else cout Initiating call to args0 MakeCall(args0, endpoint-currentCallToken); cout Press X to exit. / 取pid是我加的 for (;) pid_t thispid; char prom20; thispid = getpid(); sprintf(prom, H323 %d , thispid); cout prom cmd; if (cmd = X) break; if (cmd.FindOneOf(HYN) != P_MAX_INDEX) H323Connection*connection; /使用lock就是怕别的线程把它给删了 /因为这里正用着呢 connection=endpoint-FindConnectionWithLock(endpoint-currentCallToken); if (connection != NULL) if (cmd = H) connection-ClearCall(); else if (cmd = Y) connection-AnsweringCall(H323Connection:AnswerCallNow); else if (cmd = N) connection-AnsweringCall(H323Connection:AnswerCallDenied); connection-Unlock(); cout Exiting GetName() endl; / Main 函数结束 / 自己的Init函数 BOOL SimpleH323EndPoint:Initialise(PArgList & args) / Get local username, multiple uses of -u indicates additional aliases if (args.HasOption(u) PStringArray aliases = args.GetOptionString(u).Lines(); / 设定改Endpoint的username SetLocalUserName(aliases0); / 设定Aliases 就是每个Endpoint可以有好多名字的意思 for (PINDEX i = 1; i aliases.GetSize(); i+) AddAliasName(aliasesi); / Set the various options /设置静音检测否 SetSilenceDetectionMode(args.HasOption(e) ? H323AudioCodec:NoSilenceDetection: H323AudioCodec:AdaptiveSilenceDetection); /快速连接? DisableFastStart(args.HasOption(f); /H245通道 DisableH245Tunneling(args.HasOption(T); autoAnswer = args.HasOption(a); busyForwardParty = args.GetOptionString(B); if (args.HasOption() initialBandwidth = args.GetOptionString().AsUnsigned()*100; if (initialBandwidth = 0) cerr Illegal bandwidth specified. = 20 & jitter = 10000) SetMaxAudioDelayJitter(jitter); else cerr Jitter should be between 20 milliseconds and 10 seconds. endl; return FALSE; /设定声音设备 /也可以不用声音设备, 比如Openh323工程的子项目 OpenAM和OpenMCU /都使演示了如何不使用声音物理设备的方法, 我想那里边的东西会对某些朋友们 /的需求比较合适 if (!SetSoundDevice(args, sound, PSoundChannel:Recorder) return FALSE; if (!SetSoundDevice(args, sound, PSoundChannel:Player) return FALSE; if (!SetSoundDevice(args, sound-in, PSoundChannel:Recorder) return FALSE; if (!SetSoundDevice(args, sound-out, PSoundChannel:Player) return FALSE; / 设定decode encode的能力 / H323 EndPoint在真正进行数据通讯之前要进行能力的交换, 说明自己能够接收和发送什么标准的数据, g.711是必须支持的. / Set the default codecs available on sound cards. AddAllCapabilities(0, 0, GSM*sw); AddAllCapabilities(0, 0, G.711*sw); AddAllCapabilities(0, 0, LPC*sw); AddAllUserInputCapabilities(0, 1); RemoveCapabilities(args.GetOptionString(D).Lines(); ReorderCapabilities(args.GetOptionString(P).Lines(); cout Local username: GetLocalUserName() n Silence compression is (GetSilenceDetectionMode() = H323AudioCodec:NoSilenceDetection ? Dis : En) abledn Auto answer is autoAnswer n FastConnect is (IsFastStartDisabled() ? Dis : En) abledn H245Tunnelling is (IsH245TunnelingDisabled() ? Dis : En) abledn Jitter buffer: GetMaxAudioDelayJitter() msn Sound output device: GetSoundChannelPlayDevice() n Sound input device: GetSoundChannelRecordDevice() n Codecs (in preference order):n setprecision(2) GetCapabilities() endl; /启动一个来电的监听 /可以使用配置的端口, 也可以使用default的端口 / Start the listener thread for incoming calls. H323ListenerTCP * listener; if (args.GetOptionString(i).IsEmpty() listener = new H323ListenerTCP(*this); else PIPSocket:Address interfaceAddress(args.GetOptionString(i); listener = new H323ListenerTCP(*this, interfaceAddress); if (!StartListener(listener) cerr Could not open H.323 listener port on GetListenerPort() endl; delete listener; return FALSE; /这是连接GateKeeper相关的东西, 先不讨论了 / Initialise the security info if (args.HasOption(p) SetGatekeeperPassword(args.GetOptionString(p); cout Enabling H.235 security access to gatekeeper. endl; / Establish link with gatekeeper if required. if (args.HasOption(g) | !args.HasOption( ) H323TransportUDP * rasChannel; if (args.GetOptionString(i).IsEmpty() rasChannel = new H323TransportUDP(*this); else PIPSocket:Address interfaceAddress(args.GetOptionString(i); rasChannel = new H323TransportUDP(*this, interfaceAddress); if (args.HasOption(g) PString gkName = args.GetOptionString(g); if (SetGatekeeper(gkName, rasChannel) cout Gatekeeper set: *gatekeeper endl; else cerr Error registering with gatekeeper at gkName endl; return FALSE; else cout Searching for gatekeeper. flush; if (DiscoverGatekeeper(rasChannel) cout nGatekeeper found: *gatekeeper endl; else cerr nNo gatekeeper found. endl; if (args.HasOption( ) return FALSE; return TRUE; /设定音频设备, 没什么可讲的 BOOL SimpleH323EndPoint:SetSoundDevice(PArgList & args, const char * optionName, PSoundChannel:Directions dir) if (!args.HasOption(optionName) return TRUE; PString dev = args.GetOptionString(optionName); if (dir = PSoundChannel:Player) if (SetSoundChannelPlayDevice(dev) return TRUE; else if (SetSoundChannelRecordDevice(dev) return TRUE; cerr Device for optionName ( dev ) must be one of:n; PStringArray names = PSoundChannel:GetDeviceNames(dir); for (PINDEX i = 0; i names.GetSize(); i+) cerr namesi n; return FALSE; /这个函数很简单但是非常关键, 是从EndPoint中重载过来的. /本来是return new H323Connection()的, 现在改成Simplexxx /自己实现的一个Connection, 这样当Endpoint里面调用 /Connection的一些东西的时候, 实际上运行的是Simplexxx /的实现, 看到C+的好处了吧, C里用函数指针也可以实现, 没有 /C+这么native. H323Connection * SimpleH323EndPoint:CreateConnection(unsigned callReference) return new SimpleH323Connection(*this, callReference); /没什么东西, 关键是看看这个东西的调用的时机 BOOL SimpleH323EndPoint:OnIncomingCall(H323Connection & connection, const H323SignalPDU &, H323SignalPDU &) if (currentCallToken.IsEmpty() return TRUE; if (busyForwardParty.IsEmpty() cout Incoming call from connection.GetRemotePartyName() rejected, line busy! endl; return FALSE; cout Forwarding call to busyForwardParty . endl; return !connection.ForwardCall(busyForwardParty); /这个东西, 很有用, H323Connection的类里也有这个虚函数 /返回的值决定告诉远程的连接者是否接收这份连接请求 H323Connection:AnswerCallResponse SimpleH323EndPoint:OnAnswerCall(H323Connection & connection, const PString & caller, const H323SignalPDU &, H323SignalPDU &) currentCallToken = connection.GetCallToken(); if (autoAnswer) cout Automatically accepting call. endl; return H323Connection:AnswerCallNow; cout Incoming call from caller , answer call (Y/n)? flush; return H323Connection:AnswerCallPending; BOOL SimpleH323EndPoint:OnConnectionForwarded(H323Connection & /*connection*/, const PString & forwardParty, const H323SignalPDU & /*pdu*/) if (MakeCall(forwardParty, currentCallToken) cout Call is being forwarded to host forwardParty endl; return TRUE; cout Error forwarding call to forwardParty endl; return FALSE; /连接建立时候 void SimpleH323EndPoint:OnConnectionEstablished(H323Connection & connection, const PString & token) currentCallToken = token; cout In call with connection.GetRemotePartyName() endl; /连接断开时候 void SimpleH323EndPoint:OnConnectionCleared(H323Connection & connection, const PString & clearedCallToken) if (currentCallToken = clearedCallToken) currentCallToken = PString(); PString remoteName = + connection.GetRemotePartyName() + ; switch (connection.GetCallEndReason() case H323Connection:EndedByRemoteUser : cout remoteName has cleared the call; break; case H323Connection:EndedByCallerAbort : cout remoteName has stopped calling; break; case H323Connection:EndedByRefusal : cout remoteName did not accept your call; break; case H323Connection:EndedByNoAnswer : cout remoteName did not answer your call; break; case H323Connection:EndedByTransportFail : cout Call with remoteName ended abnormally; break; case H323Connection:EndedByCapabilityExchange : cout Could not find common codec with remoteName; break; case H323Connection:EndedByNoAccept : cout Did not accept incoming call from remoteName; break; case H323Connection:EndedByAnswerDenied : cout Refused incoming call from remoteName; break; case H323Connection:EndedByNoUser : cout Gatekeeper could find user remoteName; break; case H323Connection:EndedByNoBandwidth : cout Call to remoteName aborted, insufficient bandwidth.; break; case H323Connection:EndedByUnreachable : cout remoteName could not be reached.; break; case H323Connection:EndedByHostOffline : cout remoteName is not online.; break; case H323Connection:EndedByNoEndPoint : cout No phone running for remoteName; break; case H323Connection:EndedByConnectFail : cout Transport error calling remoteName; break; default : cout Call with remoteName completed; cout , duration setprecision(0) setw(5) (PTime() - connection.GetConnectionStartTime() endl; /打开声音设备时候 /isEncoding 表示编码吗 /编码表示向外发送数据, 从声音设备读 /解码表示从网络读出数据, 写到声音设备上 /不同的方向的codec是不同的, 所以在这里有好多文章可以做 /可以给codec attach上不同的channel根据isEncoding的值 BOOL SimpleH323EndPoint:OpenAudioChannel(H323Connection & connection, BOOL isEncoding, unsigned bufferSize, H323AudioCodec & codec) if (H323EndPoint:OpenAudioChannel(connection, isEncoding, bufferSize, codec)return TRUE; cerr Could not open sound device ; if (isEncoding) cerr GetSoundChannelRecordDevice(); else cerr GetSoundChannelPlayDevice(); cerr - Check permissions or full duplex capability. endl; return FALSE; / EndPoint的实现分析完毕. H323Connection的实现, 这个Connection的实现太简单了.可能不足以说明问题 我也没什么好说的了 / SimpleH323Connection:SimpleH323Connection(SimpleH323EndPoint & ep, unsigned ref) : H323Connection(ep, ref) BOOL SimpleH323Connection:OnStartLogicalChannel(H323Channel & channel) if (!H323Connection:OnStartLogicalChannel(channel) return
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 鱼池入股协议合同范本
- 2025年畜牧兽医考试题库及答案(综合题型)
- 计算机、IT、程序员岗位从业资格证试题库(附含答案)
- 2025年危险化学品化工自动化控制仪表作业全国考试题库(含答案)
- 糖尿病护理常规试题(附答案)
- 护理输血试题及答案
- 防诈骗法律知识测试题库(含答案)
- 《儿童护理学》考试试题及答案
- 2025年度有机茶青种植基地与茶饮连锁企业全面合作开发合同
- 2025年高端商务大厦全方位服务及员工职业发展规划合作协议
- 助听器与辅听设备基本性能及使用建议的专家共识
- 网络安全和信息化领导小组职责
- 医疗责任险产品介绍
- 中职班主任管理培训
- 高三冲刺毕业家长会课件2024-2025学年
- 运维或技术支持岗位招聘笔试题与参考答案(某大型央企)2024年
- 2023年《安徽大学学生手册》在线考试学习通超星期末考试答案章节答案2024年
- 安全评估合同
- 天津市南开区2023-2024学年六年级下学期期末数学试题
- 《全面质量管理》习题集(含答案)
- DB21T 3947-2024 普通公路装配式混凝土桥梁下部工程施工技术规范
评论
0/150
提交评论