Janus源码解析 - Janus.c

在janus中,websocket和 WebRTC之间是如何通信的

在 Janus 中,WebSocket 用于建立客户端与服务器之间的连接,而 WebRTC 用于建立浏览器之间的实时通信。具体来说,Janus 服务器会提供一个 WebSocket 接口,客户端可以通过这个接口连接到服务器。连接建立后,客户端可以向服务器发送命令,请求服务器执行相应的操作,例如创建一个新的房间、加入一个房间、发送一个消息等。

当客户端需要与其他浏览器建立实时通信时,Janus 服务器会扮演中转的角色,将数据流从一个浏览器发送到另一个浏览器。具体来说,Janus 服务器会接收 WebRTC 的 ICE 交换信息,使用这些信息建立起 WebRTC 连接,并将数据流从一个浏览器传递到另一个浏览器。这种中转模式可以穿透防火墙、NAT 等网络限制,从而实现浏览器之间的实时通信。Janus 还支持多种编解码器和音视频格式,可以适应不同的场景需求。

static struct janus_json_parameter incoming_request_parameters[] = { // 客户端请求 Janus 服务器时所必须携带的信息。
    {"transaction", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
    {"janus", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
    {"id", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
};
static struct janus_json_parameter attach_parameters[] = {
    {"plugin", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}, // 加载的插件名称,这是必须的参数
    {"opaque_id", JSON_STRING, 0}, // 用于标识此次会话
    {"loop_index", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, // 此次会话的循环计数器
};
static struct janus_json_parameter body_parameters[] = { // 用于描述 Janus 协议中客户端发送消息的参数
    {"body", JSON_OBJECT, JANUS_JSON_PARAM_REQUIRED}
};
static struct janus_json_parameter jsep_parameters[] = { // 用于描述 Janus 协议中客户端发送的 SDP 信息
    {"type", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}, // type 表示 SDP 的类型, 这是必须的参数// audio:音频流、video:视频流、application:应用程序流、message:文本或二进制消息流、data:数据量
    {"sdp", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}, // sdp 表示 SDP 的内容,也是必须的参数//协议版本(=)、原点(=)、
    {"trickle", JANUS_JSON_BOOL, 0},// 是否支持 Trickle ICE,是可选的参数 // 启用 Trickle ICE 可以加速 ICE 过程,减少客户端与服务器之间的延迟,提高 WebRTC 连接的建立速度
    {"rid_order", JSON_STRING, 0}, // 可选的 RTP 流 ID 顺序,也是可选的参数//保证远端客户端按照指定的顺序接收到媒体流,并正确解析其中的 RID
    {"force_relay", JANUS_JSON_BOOL, 0}, // 是否强制使用中继,也是可选的参数
    {"e2ee", JANUS_JSON_BOOL, 0} // 是否启用端到端加密,也是可选的参数
};

type:

audio:音频流、video:视频流、application:应用程序流、message:文本或二进制消息流、data:数据量

sdp:

1、协议版本(v=):描述 SDP 协议的版本号,一般为 0。
2、原点(o=):描述会话的原点信息,包括用户名、会话 ID、版本号等。
3、会话名称(s=):描述会话的名称。
4、时间描述(t=):描述会话的起始时间和结束时间。
5、媒体描述(m=):描述媒体流的类型、端口号、传输协议等信息。
6、媒体格式(a=rtpmap):描述媒体流的格式,包括编码器名称、采样率、比特率等。
7、带宽限制(b=):描述媒体流的带宽限制。
8、加密信息(a=):描述媒体流的加密信息,如加密算法、加密密钥等。
9、会话层描述(a=):描述会话层的特殊要求和限制,如目标地址、传输速率等。

trickle: 是否支持Trickle ICE

Trickle ICE 是一种 ICE candidate 发送机制,它允许 WebRTC 客户端在 ICE 协商过程中逐步发送 ICE 候选地址,而不是等待所有候选地址收集完成后再一次性发送。启用 Trickle ICE 可以加速 ICE 过程,减少客户端与服务器之间的延迟,提高 WebRTC 连接的建立速度。

如果开启了 Trickle ICE,Janus 将在 ICE 协商期间持续收集和发送候选地址,直到所有候选地址都被收集到或者超时时间到达。如果不开启 Trickle ICE,则需要等待所有候选地址都被收集到后,才会一次性将所有候选地址发送给远端客户端。因此,开启 Trickle ICE 可以缩短 WebRTC 连接的建立时间。

rid_order:

在 Janus WebRTC Gateway 中,rid_order 是用来控制传输 RID 的顺序的字段。当启用了 rid_order 时,Janus 会按照 rid_order 中指定的顺序对 RID 进行排序,并将排序后的 RID 传输给远端客户端。这个字段通常用于解决 Simulcast(多流发送)时的兼容性问题,确保远端客户端可以正确解析和处理多路媒体流。

例如,如果一个媒体流包含多个 Simulcast Stream,并且每个 Simulcast Stream 都有一个不同的 RID,但远端客户端不支持 Simulcast,那么启用 rid_order 就可以保证远端客户端按照指定的顺序接收到媒体流,并正确解析其中的 RID。

force_relay

在 WebRTC 中,通过 ICE(Interactive Connectivity Establishment)协议协商建立对等连接时,当两个端点不能直接相互通信时,就需要借助一个 TURN(Traversal Using Relays around NAT)/relay 服务器进行数据传输。默认情况下,WebRTC 会尽可能地尝试直接建立对等连接,只有在无法直接通信时才会使用 TURN/relay 服务器进行中转。

如果将 force_relay 参数设置为 true,就会强制 WebRTC 使用 TURN/relay 服务器进行中转,而不尝试直接建立对等连接。这通常用于解决网络环境较差或者防火墙设置比较严格的情况下,确保 WebRTC 可以正常通信。但是,强制使用 TURN/relay 服务器会增加数据传输的延迟,并增加 TURN/relay 服务器的负载。因此,应该在必要时才使用 force_relay 参数。

e2ee

启用 e2ee 参数后,Janus 将在媒体流的 SDP 中添加 SDES(Session Description Protocol Security Descriptions)加密参数,用于指定加密算法和密钥。Janus 还会协商出加密所需的密钥,并将其发送给客户端,客户端使用该密钥进行加密和解密。

需要注意的是,启用端到端加密会增加通信的延迟和复杂度,并且可能导致一些附加的负载,因为加密和解密需要占用 CPU 和网络资源。因此,应该在必要时才使用 e2ee 参数,例如在需要保护通信内容不被窃听或篡改的敏感场景下使用。

static struct janus_json_parameter add_token_parameters[] = {
    {"token", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}, // 表示要添加的身份验证令牌,类型为 JSON_STRING。这是一个必需参数,必须在 API 调用中指定该参数的值
    {"plugins", JSON_ARRAY, 0} // 示要授权给该身份验证令牌的插件列表
};
static struct janus_json_parameter token_parameters[] = {
    {"token", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
};
static struct janus_json_parameter admin_parameters[] = {
    {"transaction", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
    {"janus", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
};
static struct janus_json_parameter mnq_parameters[] = { // 用于设置 Janus WebRTC Gateway 中的最小 NACK 队列长度
    {"min_nack_queue", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}
};

NACK 队列是用于存储未收到的 RTP 数据包的缓冲区,以便在收到后重传。通过设置最小 NACK 队列长度,可以控制在什么时候开始重传 RTP 数据包。如果 NACK 队列中存储的未收到的 RTP 数据包数量小于指定的最小值,则不会进行重传。

需要注意的是,设置最小 NACK 队列长度可能会影响 Janus 的性能。如果将该值设置得太小,则可能会导致 Janus 在重新传输 RTP 数据包时变得更加频繁,从而降低系统的性能。建议根据实际需要设置该值,以确保 Janus 在保证视频质量的同时保持良好的性能。

static struct janus_json_parameter nopt_parameters[] = { // 用于设置 Janus WebRTC Gateway 中的 NACK 优化功能
    {"nack_optimizations", JANUS_JSON_BOOL, JANUS_JSON_PARAM_REQUIRED}
};

NACK 优化是一种在传输 RTP 数据包时减少网络延迟和带宽使用的技术。在启用 NACK 优化功能时,Janus 会在向客户端发送 RTP 数据包时使用一些技巧,以便在接收到 NACK 请求时能够更快地重新传输 RTP 数据包。这可以减少 RTP 数据包的传输延迟和带宽使用,并提高视频质量。

需要注意的是,启用 NACK 优化功能可能会增加 Janus 的 CPU 和内存使用量。建议根据实际需要启用或禁用该功能,以确保 Janus 在保证视频质量的同时保持良好的性能。

NACK:

NACK(Negative Acknowledgment)是一种数据包确认机制,用于检测和处理丢失的数据包。当接收方检测到缺失的数据包时,它会向发送方发送 NACK 请求,以便重新发送缺失的数据包。NACK 通常用于 RTP 数据包传输,特别是在实时音视频应用程序中,如视频会议、直播和网络电话中。

当发送方接收到 NACK 请求时,它会重新发送缺失的数据包。如果接收方继续检测到缺失的数据包,它将发送另一个 NACK 请求,直到所有丢失的数据包都被重新发送为止。通过这种方式,NACK 可以减少数据包丢失对实时音视频质量的影响,提高音视频应用程序的稳定性和性能。

需要注意的是,NACK 机制需要额外的带宽和处理能力来处理丢失的数据包,因此在设计实时音视频应用程序时需要考虑到这一点。除了 NACK 之外,还有一些其他的机制和协议可以用于实时音视频数据包传输,如 FEC(Forward Error Correction)和 RTX(Retransmission-based Transmission Control Protocol Extension)等。

static struct janus_json_parameter nmt_parameters[] = {
    {"no_media_timer", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}
};
static struct janus_json_parameter st_parameters[] = {
    {"slowlink_threshold", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}
};
slowlink_threshold

参数用于检测会话中的网络连接速度,如果连接速度过慢,则会通知应用程序进行相应的处理,例如启用 FEC、降低分辨率或帧率等。通过配置 st_parameters 参数,可以设置 Janus Gateway 中 slowlink_threshold 的值,以控制网络连接速度的检测阈值。

具体来说,st_parameters 参数中包含一个名为 slowlink_threshold 的整数值,该值表示网络连接速度的检测阈值,以 bps(比特/秒)为单位。当检测到连接速度低于 slowlink_threshold 时,Janus Gateway 将发送 slowlink 通知到应用程序,以便应用程序进行相应的处理。应用程序可以根据通知的内容采取不同的行动,例如启用 FEC、降低分辨率或帧率等,以保证良好的媒体流质量。当网络连接速度低于 slowlink_threshold 时,应用程序可以采取以下措施:
1、 启用前向纠错(FEC):通过添加冗余数据来提高数据传输的可靠性,从而减少数据包的丢失。
2、降低视频分辨率和帧率:降低视频分辨率和帧率可以减少数据传输量,从而减少网络传输时的带宽占用。
3、降低音频采样率和编码质量:降低音频采样率和编码质量可以减少音频数据的大小,从而减少网络传输时的带宽占用。

static struct janus_json_parameter ans_parameters[] = {
    {"accept", JANUS_JSON_BOOL, JANUS_JSON_PARAM_REQUIRED}
};

用于指示是否接受 offer 请求并向远程对等方发送 answer 响应。
在 WebRTC 中,answer 是在收到 offer 后创建的,以向对等方描述可用于媒体会话的本地媒体资源(例如音频和视频)。因此,通过接受或拒绝 offer 请求,answer 将确定本地资源在 WebRTC 会话中的使用方式。ans_parameters 参数数组中的 accept 参数用于控制对 offer 请求的响应,从而在媒体会话的交互中起到关键作用。

static struct janus_json_parameter querytransport_parameters[] = {
    {"transport", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
    {"request", JSON_OBJECT, 0}
};

-==-=-=-=-=-=-=-=-=
DSCP(Differentiated Services Code Point)是一种用于网络流量管理的QoS(Quality of Service)技术。它通过为数据包头部指定一个特殊的DSCP值来标记不同类型的网络流量,以便网络设备可以优先处理高优先级的流量,从而提高网络的可靠性和性能。

DTLS(Datagram Transport Layer Security)是一种基于UDP(User Datagram Protocol)的安全传输协议,它提供了与TLS(Transport Layer Security)类似的加密和认证机制,用于保护数据在不可信网络上的传输安全性。DTLS-MTU指的是DTLS协议中的最大传输单元(MTU),即一次传输的数据包的最大长度。在DTLS通信中,由于UDP协议本身的限制,数据包的大小受到MTU的限制,超过MTU的数据需要分片传输,会导致额外的延迟和开销。因此,了解DTLS-MTU的大小,可以更好地优化和管理DTLS通信的性能。

=-==-=-=-=-=-=-=-=-=-=-=-=-=--=-=-
"full trickle" ICE机制是一种用于NAT遍历的技术,在WebRTC中经常使用。

Full Trickle是一种ICE传输机制,可以提高ICE协商的速度和成功率。

在常规的Trickle ICE中,当一个peer首次向另一个peer发出ICE候选项时,它只会发送一个,然后等待回复。如果该候选项未能导致连接,则发送下一个候选项,然后等待回复。这个过程需要很长时间,因为需要依次尝试每个候选项,等待回复并决定下一个候选项。

Full Trickle可以一次性发送所有候选项,从而大大缩短协商时间。当有多个ICE候选项可用时,Full Trickle可以通过在多个网络接口(例如Wi-Fi和以太网)之间选择最佳的候选项来提高成功率。

Full Trickle的工作流程如下:

客户端发送包含所有候选项的ICE SDP offer。
服务器收到ICE SDP offer并决定最佳候选项。
服务器将选择的候选项包含在ICE SDP answer中,然后将其发送回客户端。
客户端收到ICE SDP answer,并在SDP中找到所选候选项。
客户端使用所选的候选项建立连接。
Full Trickle相比常规的Trickle ICE可以更快地建立连接,并提高成功率,但它可能会增加带宽使用和延迟。因此,Full Trickle通常用于网络环境较好的情况下。

-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-
JSEP (JavaScript Session Establishment Protocol) offer 类型的消息。JSEP 是一个用于建立 WebRTC 会话的协议,offer 和 answer 是其中的两种类型。这段代码首先将 offer 标记为 true,表示处理的是一个 offer 消息。然后设置 JANUS_ICE_HANDLE_WEBRTC_PROCESSING_OFFER 和 JANUS_ICE_HANDLE_WEBRTC_GOT_OFFER 标志位,表示正在处理一个 offer,并且已经接收到了一个 offer。同时清除 JANUS_ICE_HANDLE_WEBRTC_GOT_ANSWER 标志位,表示还没有接收到 answer 消息。

-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-

FEC是Forward Error Correction(前向纠错)的缩写,是一种数据传输错误纠正技术。在FEC中,发送方将原始数据加上冗余数据(也称为冗余码字或校验码字),并一起发送给接收方。接收方在接收到数据时,通过校验冗余数据来恢复原始数据。

FEC的实现方式有多种,最常见的是使用纠删码(Reed-Solomon Code)。纠删码通过增加校验码字,使得在接收方收到的数据发生错误时,可以通过校验码字来检测并纠正错误。例如,如果发送方发送了一个包含10个数据块和2个校验码块的数据包,接收方在接收到这个数据包时,如果发现其中1个数据块有错误,可以使用另外两个校验码块来纠正该错误,从而恢复原始数据。

FEC的优点是可以提高数据传输的可靠性,降低数据丢失率。与重传机制相比,FEC可以在数据包丢失的情况下直接恢复原始数据,而不需要进行重传,从而降低了网络延迟和带宽占用。因此,FEC在实时传输应用中得到了广泛的应用,例如视频会议和流媒体等。

=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-
RTX(Retransmission TeXt)是一种基于RTP协议的重传机制,用于解决网络丢包等问题。RTX的通信原理与过程如下:

首先,发送方在RTP报文中添加RTX相关的信息,包括原始媒体数据的SSRC(同步信源)标识、重传数据的新的SSRC标识、以及原始媒体数据的序列号和时间戳。
接收方收到RTP报文后,根据报文中的信息进行处理。如果发现丢失了某个报文,则发送NACK(Negative ACKnowledgement)给发送方,告诉其需要重传丢失的报文。
发送方接收到NACK后,根据其中的信息,重传相应的报文。这些重传的报文以原始媒体数据的SSRC标识为SSRC,以重传数据的新的SSRC标识为PT(Payload Type)值,以原始媒体数据的序列号和时间戳为基础,重新生成RTP报文并发送给接收方。
接收方收到重传的报文后,根据其序列号和时间戳进行排序和处理,并进行后续的媒体处理。
需要注意的是,RTX只能重传最近发送的几个RTP报文,因此如果发送方发送数据的速度过快,可能会导致某些报文已经被清除,无法进行重传。此外,RTX也会带来一定的延迟和带宽开销,因此需要根据具体情况进行权衡和选择。

-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-

在janus库中,ice.c文件中的这段代码定义了一个名为twcc_period的变量,它的作用是指定TWCC(Transport Wide Congestion Control)周期的默认值为200ms。TWCC是一种流量控制机制,用于帮助在网络拥塞情况下保持流量稳定,提高实时通信质量。

在Janus中,twcc_period的值将用于确定TWCC报告的发送频率。默认情况下,Janus每200ms发送一次TWCC报告,以便及时地检测网络拥塞情况,并相应地调整传输速率,以避免在实时通信过程中出现质量下降或丢包等问题。

在ice.c文件中,通过定义DEFAULT_TWCC_PERIOD和twcc_period变量,可以方便地修改TWCC周期的默认值,并通过twcc_period变量在代码中引用,以确保TWCC报告的发送频率与所需的实时通信质量相匹配。

-=-=-=-=-=-=-=-=-=--=-=-=-=-=-
在Janus库的ice.c文件中,这段代码定义了三个宏:

DEFAULT_MIN_NACK_QUEUE:指定NACK队列/重传的最小值,单位为毫秒,默认为200毫秒。
DEFAULT_MAX_NACK_QUEUE:指定NACK队列/重传的最大值,单位为毫秒,默认为1000毫秒。
MAX_NACK_IGNORE:指定重传后最大的忽略计数,单位为微秒,默认为200000微秒(即200毫秒)。
这些宏的作用是为了帮助调节Janus库在丢包情况下进行重传的行为。当Janus检测到有数据包丢失时,它将会在NACK队列中等待一段时间(DEFAULT_MIN_NACK_QUEUE),以等待丢失的数据包到达。如果这段时间内没有收到数据包,则Janus将会发送NACK请求,要求重新发送数据包。在DEFAULT_MIN_NACK_QUEUE到DEFAULT_MAX_NACK_QUEUE之间,Janus会进行一系列的NACK和重传,以尽量保证数据的完整性。

而MAX_NACK_IGNORE则指定了一个时间上限,当重传次数达到一定数量后,Janus将停止进行重传,并认为数据包已经永久丢失。这个时间上限的设置是为了避免Janus在某些极端情况下陷入死循环,同时也可以帮助控制网络拥塞和延迟,提高通信质量。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容