Liblinphone是核心引擎,这是实现Linphone所有功能的库。它是一款功能强大的基于 SIP 的 SDK,用于 IP 语音和视频,任何人都可以使用它向应用程序添加音频和视频呼叫或即时消息传递功能。它提供了一个高级 API 来发起、接收和终止音频和视频呼叫。
Liblinphone 依赖于以下软件组件:
- Mediastreamer2,一个功能强大的轻量级流媒体引擎,内容丰富的多媒体SDK,用于音频/视频流和处理 和 语音/视频电话应用程序。这个开源库负责接收和发送Linphone中的所有多媒体流,包括语音/视频捕获、编码和解码以及渲染。
- oRTP,一个简单的RTP库, 一个实现实时传输协议 ( RFC 3550 ) 的库
- belle-sip,SIP 库
- bzrtp,BZRTP 是 ZRTP 密钥交换协议( RFC6189 )的开源实现。该库是用 C 和 C++ 编写的,完全可移植, 扩展了 ZRTP 协议版本 1.1 以支持后量子密码算法
bzrtp定义
bzrtp支持的hash类型:
- ZRTP_HASH_S256 表示使用256位安全哈希算法(Secure Hash Algorithm)。通常指的是SHA-256。
- ZRTP_HASH_S384 表示使用384位安全哈希算法,即SHA-384。
- ZRTP_HASH_S512 表示使用512位安全哈希算法,即SHA-512。
- ZRTP_HASH_N256 表示使用256位非安全哈希算法(Non-secure Hash Algorithm)。具体指的是SHA-3-256。
- ZRTP_HASH_N384 表示使用384位非安全哈希算法,即SHA-3-384。
bzrtp支持的加密算法Cipher的定义,每个宏定义代表了不同的加密算法。
- ZRTP_CIPHER_AES1 表示使用AES-128加密算法。
- ZRTP_CIPHER_AES2 表示使用AES-192加密算法。
- ZRTP_CIPHER_AES3 表示使用AES-256加密算法。
- ZRTP_CIPHER_2FS1 表示使用Twofish-128加密算法。
- ZRTP_CIPHER_2FS2 表示使用Twofish-192加密算法。
- ZRTP_CIPHER_2FS3 表示使用Twofish-256加密算法。
bzrtp支持身份验证标签(Authtag)的定义:
- ZRTP_AUTHTAG_HS32 表示使用32位哈希值进行身份验证。
- ZRTP_AUTHTAG_HS80 表示使用80位哈希值进行身份验证。
- ZRTP_AUTHTAG_SK32 表示使用32位安全密钥进行身份验证。
- ZRTP_AUTHTAG_SK64 表示使用64位安全密钥进行身份验证。
关于ZRTP密钥协商算法的定义。每个宏定义代表了不同的密钥协商算法,
- ZRTP_KEYAGREEMENT_DH2k 表示使用2048位的Diffie-Hellman密钥协商。
- ZRTP_KEYAGREEMENT_X255 表示使用Curve25519曲线的Elliptic Curve Diffie-Hellman (ECDH)密钥协商。
- ZRTP_KEYAGREEMENT_DH3k 表示使用3072位的Diffie-Hellman密钥协商。
- ZRTP_KEYAGREEMENT_KYB1 到 ZRTP_KEYAGREEMENT_KYB3 表示三种不同大小的Kyber密钥协商(512位、768位和1024位)。
- ZRTP_KEYAGREEMENT_K255_KYB512 表示使用Curve25519和Kyber-512混合的密钥协商。
关于ZRTP密钥协商算法的定义。每个宏定义代表了不同的密钥协商算法。
- ZRTP_KEYAGREEMENT_Prsh 表示使用Pre-shared Key (PSK)进行密钥协商。
- ZRTP_KEYAGREEMENT_Mult 表示使用Multimedia Internet KEYing (MIKEY)协议进行密钥协商。
关于ZRTP安全认证字符串(SAS)的定义。每个宏定义代表了不同类型的安全认证字符串。
- ZRTP_SAS_B32 表示使用Base32编码表示的安全认证字符串。
- ZRTP_SAS_B256 表示使用Base256编码表示的安全认证字符串。
安全认证字符串用于在通信参与者之间进行身份验证和确认通信通道的安全性。通过使用不同的编码方式,可以以不同的形式呈现安全认证字符串
MSZrtpParams 结构包含用于控制媒体流的 ZRTP 的参数:
bzrtp流程
通过PC端和手机端app之间通信,建立视频通话,然后抓取log,可以看到bzrtp的加密相关log如下:
createStream()
StreamsGroup::createStream 根据指定类型构建音频和视频流, 如果能够正确创建音视频流,则会将 mStreams 数组中指定索引处的流设置为新建的流。然后调用 AttachMixers() 函数将任何混合器附加到Stream。
MS2AudioStream()
MS2AudioStream 类构造函数。此类负责管理 Linphone 中的音频流。MS2AudioStream 负责许多任务,包括:发送和接收音频数据包;管理音频编解码器;处理抖动和丢包;执行回声消除;管理音频设备。
initZrtp()
initZrtp()函数初始化音频流的 ZRTP以及相关参数。该函数首先会获取媒体会话的远程和本地IP地址;紧接着会清理地址以删除任何不必要的信息;之后将地址转换为字符串;然后创建一个 MSZrtpParams 对象进行初始化,调用 setZrtpCryptoTypesParameters 函数来设置 ZRTP 加密类型参数,调用audio_stream_enable_zrtp函数来启用音频流的ZRT;最后释放为peerUri 和selfUri 字符串分配的内存。
初始化时依次包括如下值:
- zidCacheDB:ZRTP 缓存数据库。
- zidCacheDBMutex:保护 ZRTP 缓存数据库的互斥锁。
- peerUri:远程对等点的 URI。
- selfUri:本地对等点的 URI。
- AcceptGoClear:指示是否接受 Go Clear 调用的标志。
- LimeKeyTimeSpan:LIME 密钥的生命周期(以秒为单位)。
setZrtpCryptoTypesParameters()
setZrtpCryptoTypesParameters 设置 ZRTP 加密类型参数,通常在首次创建音频流时调用。
linphone_core_get_srtp_crypto_suites()
linphone_core_get_srtp_crypto_suites() 返回 Linphone 核心支持的 SRTP 加密套件的字符串表示形式:
audio_stream_enable_zrtp()
audio_stream_enable_zrtp() 函数在音频流上启用 ZRTP:
检查audio Stream是否已有 ZRTP 上下文。如果没有,它将使用 ms_zrtp_context_new() 函数创建一个新的。
如果流尚未受到保护,则会使用 ms_zrtp_reset_transmition_timer() 函数重置 ZRTP 传输计时器。
ms_zrtp_context_new()
ms_zrtp_context_new() 函数通常在首次创建媒体流会话时调用。该函数为媒体流会话创建新的 ZRTP 上下文,并使用指定的参数配置上下文。
ms_zrtp_configure_context() 函数通常在创建并初始化 ZRTP 上下文后调用,用于配置 ZRTP 上下文以使用指定的 RTP 和 RTCP 传输。
由于构建AudioStream还需要配置其他东西,在此不做特别关注,仅仅和zrtp相关的部分。
video initZrtp()
VideoStream部分和Audio基本差不多。MS2VideoStream::initZrtp() 初始化视频流的 ZRTP,通常在首次创建视频流时调用。
需要特别说明的是:如果音频流不存在,initZrtp()函数将记录错误消息并返回。这是因为视频的 ZRTP 需要依赖音频流的context才能发挥作用。
video_stream_enable_zrtp()
video_stream_enable_zrtp() 使用来自音频流的信息在视频流上启用 ZRTP
该函数首先检查音频流是否具有 ZRTP 上下文。如果音频流具有 ZRTP 上下文,而视频流没有 ZRTP 上下文,则该函数将调用 ms_zrtp_multistream_new() 函数,使用音频流的 ZRTP 上下文作为参考,为视频流创建新的 ZRTP 上下文。如果视频流已经具有 ZRTP 上下文并且视频流不受保护,则该函数调用 ms_zrtp_reset_transmition_timer() 函数来重置 ZRTP 传输计时器。
ms_zrtp_multistream_new()
函数 ms_zrtp_multistream_new() 使用指定的活动 ZRTP 上下文作为参考,为指定的媒体流会话创建新的多流 ZRTP 上下文。
首先调用 bzrtp_addChannel() 函数将媒体流会话的 RTP 会话添加到活动 ZRTP 上下文中。 接着创建一个新的 MSZrtpContext 对象并将其链接到活动的 ZRTP 上下文。MSZrtpContext 对象包含有关 ZRTP 上下文的附加信息,例如媒体流会话和自身 SSRC。
然后,将多流 ZRTP 上下文的客户端数据设置为 MSZrtpContext 对象。客户端数据用于将 MSZrtpContext 对象与媒体流会话关联。
最后,该调用ms_zrtp_configure_context()函数来配置多流ZRTP上下文。
这样音频和视频都完成zrtp的初始化了。
start流程
主叫流程从接收到ack开始
而被叫流程也基本类似,最后也是走到updatestreams,不作为本文重点不再详细展开,后续有时间再把该部分整理一下。
MS2AudioStream::startZrtp()
MS2AudioStream::startZrtp() 启动音频流的 ZRTP 通道。 该函数首先检查音频流是否具有 ZRTP 上下文。如果音频流没有 ZRTP 上下文,则该函数调用 initZrtp() 函数来初始化音频流的 ZRTP。ZRTP上下文初始化后,该函数调用audio_stream_start_zrtp()函数来启动ZRTP通道。
audio_stream_start_zrtp()
audio_stream_start_zrtp()启动指定音频流的ZRTP通道。 该函数首先检查音频流是否具有 ZRTP 上下文。如果音频流具有 ZRTP 上下文,则该函数调用 ms_zrtp_channel_start() 函数来启动 ZRTP 通道。如果ms_zrtp_channel_start()函数返回错误代码MSZRTP_ERROR_CHANNEL_ALREADY_STARTED,则该函数调用ms_zrtp_reset_transmition_timer()函数重置ZRTP传输定时器。
MS2VideoStream::startZrtp()
MS2VideoStream::startZrtp() 启动视频流的 ZRTP 通道。该函数首先检查视频流的媒体会话是否支持 ZRTP 加密。如果视频流的媒体会话支持 ZRTP 加密,则该函数将检查视频流是否具有 ZRTP 上下文。如果视频流没有ZRTP上下文,则该函数调用initZrtp()函数来初始化视频流的ZRTP。
ZRTP上下文初始化后,该函数调用video_stream_start_zrtp()函数来启动ZRTP通道。
video_stream_start_zrtp()
video_stream_start_zrtp() 启动指定视频流的 ZRTP 通道。 该函数首先检查视频流是否具有 ZRTP 上下文。如果视频流具有 ZRTP 上下文,则该函数会调用 ms_zrtp_channel_start() 函数来启动 ZRTP 通道。如果ms_zrtp_channel_start()函数返回错误代码MSZRTP_ERROR_CHANNEL_ALREADY_STARTED,则该函数调用ms_zrtp_reset_transmition_timer()函数重置ZRTP传输定时器。
接下来就是bzrtp库的接口了,下篇文章继续解读,欢迎持续关注。
参考资料
https://blog.csdn.net/forest_world/article/details/51517772
https://www.linphone.org/technical-corner/linphone
https://gitlab.linphone.org/BC/public
我是一枚爱跑步的程序猿,维护公众号和知乎专栏《MediaStack》,有兴趣可以关注,一起学习音视频知识,时不时分享实战经验。
版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。