pjsip中面向对象思路

  百度百科中对“面向对象”的解释为:面向对象(Object Oriented,OO)是软件开发方法。面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统网络管理结构、CAD技术、人工智能等领域。面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术 发展到一定阶段后的产物。

 

         C语言是一门通用计算机编程语言,应用广泛。它的设计目标是提供一种能以简易的方式编译、处理低级存储器产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。最初设计C语言目的是为编写Unix操作系统。

 

处理器能够真正“认识”的只有机器码,任何计算机语言都要最终生成生理器能够识别的机器码。所以从这个角度看,面向结构的C语言与面向对象的C++、Java、C#、Python等语言所表现的不同语法,只是为了方便解决不同领域问题。但面向对象与面向结构的使用习惯毕竟迥异,尤其是使用习惯了Java、C#等不允许使用指针、动态分配内存等人员,在学习实践pjproject-2.x的C语言实现时,难免有些不适应,本文通过将pjsip中C语言实现与Java/C#等面向对象的思路作对比,以面向对象的习惯用法来理解pjsipC语言实现

 

一、指针

a) 内存地址

  计算机中所有的数据都必须放在内存中,不同类型的数据占用的字节数不一样,例如 int 占用4个字节,char 占用1个字节。为了正确地访问这些数据,必须为每个字节都编上号码,就像门牌号、身份证号一样,每个字节的编号是唯一的,根据编号可以准确地找到某个字节。


  我们将内存中字节的编号称为地址(Address)或指针(Pointer)。地址从 0 开始依次增加,对于 32 位环境,程序能够使用的内存为 4GB,最小的地址为 0,最大的地址为 0XFFFFFFFF。

b)  都是地址

  数据和代码都以二进制的形式存储在内存中,计算机无法从格式上区分某块内存到底存储的是数据还是代码。C语言编译器在编译过程中通常会生成:代码段、数据段、堆栈段、附加段。当程序被加载到内存后,操作系统会给不同的内存块指定不同的权限,拥有读取和执行权限的内存块就是代码,而拥有读取和写入权限(也可能只有读取权限)的内存块就是数据。

  CPU 访问内存时需要的是地址,而不是变量名和函数名!变量名和函数名只是地址的一种助记符,当源文件被编译和链接成可执行程序后,它们都会被替换成地址。编译和链接过程的一项重要任务就是找到这些名称所对应的地址。虽然变量名、函数名、字符串名和数组名在本质上是一样的,它们都是地址的助记符,但在编写代码的过程中,我们认为变量名表示的是数据本身,而函数名、字符串名和数组名表示的是代码块或数据块的首地址。

c)  C语法中的指针

  指针(Pointer)就是内存的地址,C语言允许用一个变量来存放指针,这种变量称为指针变量。指针变量可以存放基本类型数据的地址(一个整型数),也可以存放数组、函数以及其他指针变量的地址(一个整型数)。

  指针变量内存放的是内存地址(一个整型数),因此它在(32位CPU)内存中的长度为32bit,即4个字节。下列为常见指针变量的定义:

定义                             含义

int *p;                         p可以指向 int 类型的数据

float *p;                      p可以指向 float 类型的数据

int **p;                       p为二级指针,指向 int *类型的数据。

int *p();                       p是一个函数,它的返回值类型为int *。

int (*p)();                    p是一个函数指针,指向原型为int func() 的函数。

 

  指针变量本质上是整型变量,存放的内容为其它变量或函数的在内地址。之所以有上述多种类型的指针是为了让编译器在编译时,按指针指向类型的长度进行内存地址操作。例如下列结构:

typedef long           pj_ssize_t;

struct pj_str_t

{

            /** Buffer pointer, which is by convention NOT null terminated. */

            char       *ptr;

            /** The length of the string. */

            pj_ssize_t  slen;

};

  32位CPU下,pj_str_t中 char *prt是一个字符指针,4个字节,存放指向内存中字符串的首地址,pj_ssize_t slen是一个长整型变量,8个字节。如果声明一个上述结构的指南针:struct pjstr_t *pj_str1;当这个指针指向一个内存地址0x1000000的struct pjstr_t实例时,pj_str1->slen的地址就是0x1000000+4,即这个结构的首地址0x1000000开始跨越char *prt的长度~4字节。


二、结构

  C#语言也存在struct,它与class的区别是:struct内的属性变量缺省为public,而class内的属性变量缺省为private。在C语言内,也可以使用结构体(struct)来存放一组不同类型的数据和函数指针。

typedef struct pjmedia_port

{

pjmedia_port_info    info;

 

    struct port_data {

   void        *pdata;

   long        ldata;

    } port_data;

 

    pjmedia_clock_src* (*get_clock_src)(struct pjmedia_port *this_port, pjmedia_dir dir);

    pj_status_t(*put_frame)(struct pjmedia_port *this_port, pjmedia_frame *frame);

 

   pj_status_t(*get_frame)(struct pjmedia_port *this_port, pjmedia_frame *frame);

 

   pj_status_t(*on_destroy)(struct pjmedia_port *this_port);

} pjmedia_port;

  上述媒体端口pjmedia_port结构内存放与媒体端口相关的数据:媒体端口信息 info、端口数据 port_data。和回调函数指针:取时钟源get_clock_src、推帧数据put_frame、取帧数据get_frame、销毁时on_destory。


三、方法

a) 接口

  Java、C#中的接口(interface)是为了规范一组方法,是用来定义对象之间通信的契约。在软件设计中有一个非常重要的原则就是:面向接口编程,依赖于接口或抽象层。Pjsip的C语言实现中体现了上述思想,例如对于媒体传输端口,有UDP、ICE、SRTP等多种实现方式,这几种实现方式实现相同功能,这些功能被定义为类似“接口”:

struct pjmedia_transport_op

{

        pj_status_t (*get_info)(pjmedia_transport *tp,pjmedia_transport_info *info);

 

        pj_status_t (*attach)(pjmedia_transport *tp,

              void *user_data,

              const pj_sockaddr_t *rem_addr,

              const pj_sockaddr_t *rem_rtcp,

              unsigned addr_len,

              void (*rtp_cb)(void *user_data,void *pkt,pj_ssize_t size),

              void (*rtcp_cb)(void *user_data,void *pkt,pj_ssize_t size));

 

void (*detach)(pjmedia_transport *tp,void *user_data);

 

       pj_status_t (*send_rtp)(pjmedia_transport *tp,const void *pkt,pj_size_t size);

 

    pj_status_t (*send_rtcp)(pjmedia_transport *tp,const void *pkt,pj_size_t size);

 

    pj_status_t (*send_rtcp2)(pjmedia_transport *tp,

                  const pj_sockaddr_t *addr,

                  unsigned addr_len,

                  const void *pkt,

                  pj_size_t size);

 

        pj_status_t (*media_create)(pjmedia_transport *tp,

                pj_pool_t *sdp_pool,

                unsigned options,

                const pjmedia_sdp_session *remote_sdp,

                unsigned media_index);

 

       pj_status_t (*encode_sdp)(pjmedia_transport *tp,

                  pj_pool_t *sdp_pool,

                  pjmedia_sdp_session *sdp_local,

                  const pjmedia_sdp_session *rem_sdp,

                  unsigned media_index);

 

       pj_status_t (*media_start) (pjmedia_transport *tp,

                    pj_pool_t *tmp_pool,

                    const pjmedia_sdp_session *sdp_local,

                    const pjmedia_sdp_session*sdp_remote,

                unsigned media_index);

 

       pj_status_t(*media_stop)  (pjmedia_transport *tp);

 

       pj_status_t(*simulate_lost)(pjmedia_transport *tp,

                 pjmedia_dir dir,

                 unsigned pct_lost);

 

       pj_status_t (*destroy)(pjmedia_transport *tp);

 

       pj_status_t (*attach2)(pjmedia_transport *tp,

               pjmedia_transport_attach_param *att_param);

};

  上述结构pjmedia_transport_op中定义的回调函数,在transport_udp.c、transport_ice.c、transport_srtp.c与transport_loop.c中按各自特点实现。

 

b)“类定义”

  在下面的pjmedia_transport“类”中,包含了媒体传输端口名称name、媒体传输端口类型type、相关数据user_data等“属性”和上面的pjmedia_transport_op定义的多个媒体传输端口“操作方法”。

struct pjmedia_transport

{

    char           name[PJ_MAX_OBJ_NAME];

    pjmedia_transport_type   type;

    pjmedia_transport_op    *op;

    void           *user_data;

};

 

  关于媒体传输端口的详细介绍请参考本人的媒体传输端口(pjmedia_transport)


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值