海思3518E开发笔记3.4——ORTP源码分析

ORTP库概览

  • 库提供一堆功能函数(本身没有main),都在src目录下

  • 库的使用给了案例(有main),在src/tests目录下

  • 相关数据结构和头文件,在include/ortp目录下

  • ortp实现了rtp和rtcp协议,前者负责传输,后者负责控制和同步协调

ORTP库sample分析

在音视频项目使用的比较多的就是使用rtp传输视频流,参考的代码是src/tests/rtpsend.c

首先对命令行参数的传参依次进行处理,接着就是对ortp内部函数进行调用


ortp_init

if (ortp_initialized) return;
	ortp_initialized++;

这是个bool变量,如果第一次调用则变为1,第二次重复初始化则退出

接下来调用了av_profile_init(&av_profile);,将要用到的数据结构进行填充。文件中包含很多格式,用户需要将自己需要的添加至数据结构中
在这里插入图片描述
比如我们用到h264就将h264添加其中,添加的少好处是处理起来效率更高
如果是高度定制化的产品,那么就只需要留下自己需要的就行;通用型产品就需要多放一些

初始化中的第二个函数是ortp_global_stats_reset,看名字就知道,是用于将全局变量初始化赋初值

第三个函数init_random_number_generator,顾名思义,是一个随机数发生器,说明后面有地方会用到随机数,于是在这里进行初始化


ortp_scheduler_init
初始化下面的一个函数,它是ORTP调度器,即仲裁机构,调度的是资源的分配,其功能是在一个任务中完成多个会话的发送和接收,类似于select

函数内部是一个定时器,时间到了进行下一个任务,有点类似rtos

ortp源码中的定时器是用来管理会话的,就是发送端与接收端之间的通信,会话的本质是一个结构体,用于管理很多信息
ortp库中可以同时支持多路会话,但是当前发送哪一路会话的内容,就需要我们的调度器去进行调度。


ortp_set_log_level_mask记录log


rtp_session_new
创建一路会话,会话的本质是一个结构体的实例化,该结构体管理很多信息。

接着是设置一系列的会话属性

  • rtp_session_set_scheduling_mode
    设置调度模式
  • rtp_session_set_blocking_mode
    设置阻塞模式
  • rtp_session_set_connected_mode
    设置连接模式(tcp/udp)
  • rtp_session_set_remote_addr
    设置远程ip地址和端口号
  • rtp_session_set_payload_type
    设置当前会话payload格式

接着对SSRC全局变量进行读取,如果能够读取成功,就对其进行设置

	ssrc=getenv("SSRC");
	if (ssrc!=NULL) {
		printf("using SSRC=%i.\n",atoi(ssrc));
		rtp_session_set_ssrc(session,atoi(ssrc));
	}

SSRC(源同步标识码)实际上是一个32位的int类型,用于标注接收到的一包数据的来源,在多路session中能够准确判断发送端。

要不要使用SSRC就要看实际应用中是否需要抓出一包数据进行来源的判断,比如做一些通信中的检测、统计。


接着通过传入参数argv[1]的文件名,对文件进行读取。将文件中的内容读到buffer中

调用rtp_session_send_with_ts将buffer的内容往外发,ORTP的所有秘密的内容都在这个里面
传入的参数如下

  • session——目标会话
  • bufer——传输的内容
  • len——长度
  • userts——uset_timestamps,用户时间戳
    发送方和接收方的时间可能是不同步的,比如电脑里的时间可能是错的,get时间就会错,以user开头是指时间为发送方的时间不是真正准确的时间。有可能接收方的时间比发送方还要早,所以通信中要同步发送方和接收方的时间。

该函数代码如下

int rtp_session_send_with_ts (RtpSession * session, const uint8_t * buffer, int len,
			  uint32_t userts)
{
	mblk_t *m;
	int err;
#ifdef USE_SENDMSG
	m=rtp_session_create_packet_with_data(session,(uint8_t*)buffer,len,NULL);
#else
	m = rtp_session_create_packet(session,RTP_FIXED_HEADER_SIZE,(uint8_t*)buffer,len);
#endif
	err=rtp_session_sendm_with_ts(session,m,userts);
	return err;
}

rtp_session_create_packet_with_datartp_session_create_packet多了数据

实际发送的message是mblk_t *m;不是buffer,在网络传输中是分包发送的,需要给数据包添加包头信息、包围信息甚至有校验信息。

上面两个函数实际上就是生成实际通过ortp传输的数据包。
rtp_session_create_packet为例
在这里插入图片描述
可以看到函数中首先申请空间,然后填充包头,计算好尺寸之后返回实际ortp传输的数据包

函数最后调用rtp_session_sendm_with_ts,里面包了__rtp_session_sendm_with_ts。两个下划线的函数是开源包内部自己用的,使用者一半不需要进去再进行修改。
简单进行阅读。

gettimeofday(&session->last_recv_time, NULL);

时间戳最终是通过系统API进行生成的

将初始化后的last_recv_time设置为首次发送时间
接下来

  • 如果选择阻塞模式,那么就挂起进程,直到调度器调度发送下一个数据包
  • 如果队列中数据包的时间戳早于当前时间,那么使用者不能阻塞

下面对发送的包进行判断,如果包是空的,那么表示只想阻塞

然后将传入的timestamp信息放到rtp包头中

rtp->timestamp=packet_ts;

后面记录session信息,如一共发送了多少次、payload是什么
然后传入session和数据包给rtp_session_rtp_send函数进行发送。

实际发送的函数为rtp_session_rtp_send,内部是socket实现的
在这里插入图片描述
可以看到session中有一个socket,肯定是前面某个地方打开了socket通道,然后将socket num放在了session中。

由于下面使用了send to,所以可以判断,这个socket用的是udp

实际底层实现就是socket,参考rtpsession_inet.c

ORTP库中的一些细节

  • port.c中对OS的常用机制(任务创建和销毁、进程管理和信号量等)进行了封装(linux和windows使用不同的封装),便于将ortp移植到不同平台中。

  • utils.c是一些实用工具函数,其中实现了一个双向链表(标准C库中的实现不是很好)

  • str_util.c中实现了一个队列管理

  • rtpparse.c和rtcpparse.c文件实现了解析收到的rtp数据包的部分

  • jitterctl.c中实现了jitter buffer来防抖。
    jitter buffer技术是ip 音视频通信里相对比较高级的主题,jitter buffer模块好坏通常是衡量一个voip客户端/服务器好坏的技术点之一,尤其是在网络抖动比较严重,如3g, wifi环境,数据包的rtt值不均衡往往会导致语音卡顿,丢字等现象,jitter buffer 模块通过缓存一段数据包,把数据包重排,并均匀的送给播放端,一个好的jitter buffer实现通长是动态调整缓存大小的,在网络延迟大,抖动严重时会动态增加缓存大小,在网络恢复时动态减小缓存大小以减少端到端的播放延迟。
    通俗点就是,丢包的时候,根据前后的数据模拟出丢调包的数据,使得实际得到的数据更平滑

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Spark!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值