当前位置: 首页 > news >正文

音视频入门基础:RTCP专题(2)——RTCP协议简介(上)

一、引言

本文对RTCP协议进行简介。在简介之前,请各位先下载RTCP的官方文档《RFC 3550》。《RFC 3550》总共有89页。本文下面所说的“页数”是指在pdf阅读器中显示的页数:

二、RTCP协议简介

本段内容对应《RFC 3550》的第6节。根据《RFC 3550》第17页,RTCP使用与数据包相同的分发机制,定期向会话(session)中的所有参与者发送控制包。底层协议必须提供数据包和控制包的复用,例如使用UDP的独立端口号。RTCP执行四项功能:

1.其主要功能是就数据分发的质量提供反馈。这是RTP作为传输协议不可分割的一部分,与其他传输协议的流量和拥塞控制功能相关。反馈对于控制自适应编码(adaptive encodings)可能直接有用,但IP组播的实验表明,从接收方获得反馈对于诊断分发中的故障也至关重要。向所有参与者发送接收反馈报告可以让观察到问题的人评估这些问题是局部的还是全局的。有了IP组播这样的分发机制,不参与会话的实体(如网络服务提供商)也可以接收反馈信息,并充当诊断网络问题的第三方监控者。这种反馈功能由RTCP发送方和接收方报告执行,《RFC 3550》第6.4节将对此进行描述。

2.RTCP为RTP源提供一个持久的传输级标识符(transport-level identifier),称为规范名称(canonical name)或CNAME(见《RFC 3550》第6.5.1节)。由于SSRC标识符(SSRC identifier)可能会在发现冲突或重新启动程序时发生变化,因此接收方需要CNAME来识别每个RTP源。冲突或重新启动程序时,SSRC标识符可能会发生变化,因此接收方需要CNAME来跟踪每个参与者。接收方还可能需要CNAME来将来自特定参与方的多个数据流在一组相关的RTP会话(RTP sessions)中将给定参与者的多个数据流关联起来,例如同步音频和视频。媒体间同步还需要数据发送方在RTCP数据包中包含NTP和RTP时间戳。

3.前两个功能要求所有参与者都发送RTCP数据包,因此必须控制速率,以便RTP能够扩展到大量参与者。通过让每个参与者向所有其他参与者发送控制数据包(control packets),每个参与者都可以独立观察参与者的数量。这一数字用于计算数据包的发送速率,详见《RFC 3550》第6.2 节。

4.第四个可选功能是传递最基本的会话控制信息(session control information),例如将在用户界面上显示的与会者标识。这在 “松散控制 (loosely controlled)”会话中最有可能发挥作用,因为在这种会话中,参与者的进入和离开都不需要成员控制或参数协商。RTCP可作为联系所有参与者的便捷通道,但不一定能支持应用程序的所有控制通信要求。可能需要更高级别的会话控制协议(session control protocol),这超出了《RFC 3550》的范围:

上述功能1到3应在所有环境中使用,尤其是在IP组播环境(IP multicast environment)中。RTP应用程序设计人员应避免使用只能在单播模式(unicast mode)下工作且无法扩展到更大数量的机制。如《RFC 3550》第6.2节所述,RTCP的传输可分别控制发送方和接收方,以应对无法从接收方获得反馈的单向链路等情况。

非规范性说明:在称为特定源组播(Source-Specific Multicast,简称SSM)的组播路由方法中,每个 “通道(channel)”(源地址、组地址对)只有一个发送方,接收方(通道源除外)不能使用组播与其他通道成员直接通信。此处的建议仅通过《RFC 3550》第6.2节完全关闭接收器RTCP的选项来适应SSM。未来的工作(《RFC 3550》之后的文档)将明确规定RTCP对SSM的适应性,以便保持接收方的反馈。

三、RTCP packet

根据《RFC 3550》第8页,RTCP packet是一种控制包,由固定的报头部分(fixed header)组成,类似于RTP数据包的报头部分,后面的结构元素因RTCP包类型(RTCP packet type)而异。通常情况下,多个RTCP数据包作为复合RTCP 数据包一起发送到底层协议的单个数据包中;每个RTCP数据包固定报头( fixed header)中的长度字段(length field)使其成为可能:

四、RTP session

根据《RFC 3550》第9页,RTP session(RTP会话)是与RTP通信的一组参与者之间的关联。一个参与者可能同时参与多个RTP会话。在多媒体会话中,除非编码本身将多种媒体复用为单一数据流,否则每种媒体通常在单独的RTP会话中使用自己的RTCP数据包进行传输。参与者通过使用不同的目标传输地址对接收不同的会话来区分多个RTP会话,其中传输地址对包括一个网络地址和一对用于RTP和RTCP的端口。RTP会话中的所有参与者可以共享一个共同的目标传输地址对(如IP 组播),或者每个参与者的传输地址对都不同(如单播网络地址和端口对)。在单播情况下,参与者可以使用相同的端口对(pair of ports)从会话中的所有其他参与者接收信息,也可以为每个参与者使用不同的端口对。

RTP 会话的显著特点是每个会话都有一个完整、独立的SSRC标识符空间(space of SSRC identifiers,详情见《音视频入门基础:RTP专题(7)——RTP协议简介》)。包含在一个RTP会话中的参与者集合包括那些可以接收由任何一个参与者在RTP中作为SSRC或CSRC或在RTCP中传输的SSRC标识符的参与者。例如,考虑一个使用单播UDP实现的三方会议,每个参与者在不同的端口对上接收来自其他两个参与者的信息。如果每个与会者只向另一个与会者发送关于从该与会者接收到的数据的RTCP反馈,那么会议就由三个独立的点对点RTP会话组成。如果每个与会者都向其他两个与会者提供关于接收到其他一个与会者数据的RTCP反馈,则会议由一个多方RTP会话组成。后一种情况模拟了三个参与者之间进行IP组播通信时的行为。RTP框架允许这里定义的各种变化,但特定的控制协议或应用程序设计通常会对这些变化施加限制。

五、RTCP Packet Format

本段内容对应《RFC 3550》的第6.1节。根据《RFC 3550》第18页,《RFC 3550》定义了多种RTCP数据包类型,用于传输各种控制信息:

SR:Sender report(发送方报告),用于激活发送方参与者的发送和接收统计数据。

RR:Receiver report(接收器报告),用于未激活发送方参与者的接收统计,与SR结合使用,用于激活Sender report超过31个源的情况。

SDES: Source description items(源描述项目),包括CNAME。

BYE:表示参与活动的结束。

APP: 特定于应用程序的功能。

每个RTCP数据包的开头都有一个与RTP数据包类似的固定部分,然后是结构化元素(structured elements),结构化元素的长度可根据数据包类型(packet type)而变化,但必须以32位边界结束。每个数据包的固定部分都包含对齐要求和长度字段(length field),以使RTCP 数据包 “可堆叠”。多个RTCP数据包可以串联起来,中间不加任何分隔符,形成一个复合RTCP数据包(compound RTCP packet),在下层协议(如UDP)的单个数据包中发送。复合数据包中没有明确的单个RTCP数据包计数,因为下层协议会提供一个总长度来确定复合数据包的结束。

复合数据包(compound packet)中的每个RTCP数据包都可以独立处理,对数据包的顺序或组合没有要求。但是,为了执行协议的功能,必须遵守以下限制:

1.在带宽允许的情况下,应尽可能频繁地发送接收统计数据(SR或RR),以最大限度地提高统计数据的分辨率,因此每个定期传输的复合RTCP数据包都必须包含一个报告数据包(report packet)。

2.新接收器需要尽快收到信源的CNAME,以识别信源并开始关联媒体,从而实现唇形同步(唇形同步任务指的是输入一段视频和目标音频,模型需要将视频中人物的口型变换到与音频同步的状态)等目的,因此每个复合RTCP数据包也必须包含SDES CNAME,除非复合RTCP数据包被拆分用于《RFC 3550》第9.1节所述的部分加密。

3.需要限制复合数据包中可能首先出现的数据包类型的数量,以增加第一个字中恒定位(constant bits)的数量,并提高针对错误地址的RTP数据包或其他无关数据包成功验证RTCP数据包的概率。

因此,所有RTCP数据包都必须以至少两个单独数据包的复合数据包形式发送,格式如下:

Encryption prefix:加密前缀。如果且仅如果复合数据包要根据《RFC 3550》第9.1节中的方法进行加密,则必须为每个传输的复合数据包添加一个重新绘制的32位随机数量作为前缀。如果加密需要填充,则必须将其添加到复合数据包的最后一个数据包中。

SR or RR:复合数据包中的第一个RTCP数据包必须始终是报告数据包(report packet),以方便进行《RFC 3550》的附录A.2中所述的报头验证。即使没有发送或接收数据(在这种情况下必须发送空的RR),即使复合数据包中唯一的其他RTCP数据包是BYE,情况也是如此。

Additional RRs:额外的RR。如果报告接收统计信息的信源数量超过31个,即一个SR或RR数据包所能容纳的数量,则应在初始报告数据包之后添加额外的RR数据包。

SDES: 每个复合RTCP数据包中必须包含一个包含CNAME项目的SDES数据包,《RFC 3550》第9.1节所述情况除外。如果特定应用需要,也可根据带宽限制选择包含其他源描述项(见《RFC 3550》第 6.3.9 节)。

BYE or APP: 其他RTCP数据包类型(包括尚未定义的类型)可按任意顺序排列,但BYE应是使用给定SSRC/CSRC发送的最后一个数据包。数据包类型可出现多次。

为了正确估算每个参与者的 RTCP带宽(见《RFC 3550》第6.2节),单个RTP参与者在每个报告间隔内应只发送一个复合RTCP数据包,除非复合RTCP数据包被分割用于《RFC 3550》第9.1节所述的部分加密。如果信号源太多,无法在不超过网络路径最大传输单元 (MTU) 的情况下将所有必要的RR数据包装入一个复合RTCP数据包,则每个间隔中只应包含能装入一个MTU的子集。应在多个时间间隔内循环选择子集,以便报告所有来源。

建议转换器(translators)和混合器(mixers)在可行的情况下将转发的多个来源的单个RTCP数据包合并为一个复合数据包,以分摊数据包开销。下图显示了混合器可能产生的RTCP复合数据包示例。如果复合数据包的总长度超过网络路径的MTU,则应将其分割成多个较短的复合数据包,在底层协议的单独数据包中传输。这不会影响RTCP带宽估算,因为每个复合数据包至少代表一个不同的参与者。

系统实施应忽略未知类型的RTCP 数据包。其他RTCP数据包类型可向互联网编号分配机构 (IANA) 注册:

六、RTCP Transmission Interval

该节对应《RFC 3550》的第6.2节。根据《RFC 3550》第20页,RTP的设计目的是让应用程序能够自动扩展会话规模,从几个与会者到数千人不等。例如,在音频会议中,数据流量本身就具有自我限制性(self-limiting),因为每次只有一两个人发言,所以采用组播分发后,任何给定链路上的数据传输速率都会保持相对恒定,与与会者人数无关。因此,必须通过动态计算RTCP数据包传输之间的间隔来降低传输速率。

对于每个会话,假定数据流量有一个被称为 “会话带宽(session bandwidth) ”的总限制,在参与者之间分配。该带宽可由网络预留并强制执行。如果没有预留带宽,则可能会有其他限制(视环境而定)来确定会话使用的 “合理 ”最大值,这就是会话带宽。会话带宽可根据成本或会话可用网络带宽的先验知识来选择。它在某种程度上与媒体编码无关,但编码选择可能受到会话带宽的限制。通常情况下,会话带宽是预期同时活动的发送方的标称带宽之和。对于电话会议音频,这个数字通常是一个发送方的带宽。对于分层编码,每一层都是一个独立的RTP会话,有自己的会话带宽参数。

会话带宽参数预计由会话管理应用程序在调用媒体应用程序时提供,但媒体应用程序可根据会话所选编码的单端数据带宽设置默认值。应用程序还可根据组播范围规则或其他标准执行带宽限制。所有参与者必须使用相同的会话带宽值,以便计算出相同的RTCP时间间隔(RTCP interval)。

控制和数据流量的带宽计算包括低层传输和网络协议(如UDP和IP),因为这是资源预订系统(resource reservation system)需要了解的内容。计算中不包括链路层标头(Link level headers),因为数据包在传输过程中会使用不同的链路层标头进行封装。

控制流量(control traffic)应限制在会话带宽(session bandwidth)的一小部分已知带宽内:一小部分带宽可确保传输协议传输数据的主要功能不受影响;已知带宽可确保控制流量包含在资源预留协议的带宽规格中,并确保每个参与者都能独立计算出自己的份额。控制流量带宽是数据流量会话带宽的补充。建议为RTCP增加的会话带宽比例固定为5%。此外,还建议将RTCP带宽的1/4专用于发送数据的参与者,以便在接收者数量多而发送者数量少的会话中,新加入的参与者能更快地接收到发送站点的CNAME。当发送者的比例大于参与者的1/4 时,发送者就能按比例获得全部 RTCP带宽。虽然这些常数和其他常数在时间间隔计算中的值并不重要,但会话中的所有参与者都必须使用相同的值,以便计算出相同的时间间隔。因此,应针对特定配置文件固定这些常量。

配置文件(profile)可指定控制流量带宽作为会话的单独参数,而不是会话带宽的严格百分比。使用单独参数允许速率自适应应用(rateadaptive applications)设置与 “典型 ”数据带宽一致的 RTCP带宽,该带宽低于会话带宽参数指定的最大带宽。

配置文件(profile)可进一步规定,控制流量带宽可分为两个独立的会话参数,分别用于活跃数据发送者(active data senders)和非活跃数据发送者的参与方;我们将这两个参数分别称为S和 R。根据将RTCP带宽的1/4专用于数据发送者的建议,这两个参数的建议默认值分别为1.25%和 3.75%。当发送方的比例大于参与者的 S/(S + R)时,发送方将获得这两个参数之和的相应比例。使用这两个参数可以将非数据发送方的RTCP带宽设置为零,同时保持数据发送方的RTCP带宽不为零,这样就可以在特定会话中完全关闭RTCP接收报告(RTCP reception reports),从而仍可发送发送方报告(sender reports)以进行媒体间同步。不建议关闭RTCP接收报告,因为《RFC 3550》第6节开头列出的功能需要这些报告,特别是接收质量反馈(quality feedback)和拥塞控制(congestion control)。不过,对于在单向链路上运行的系统或不需要接收质量反馈或接收器有效性反馈的会话,以及有其他方法避免拥塞的系统来说,关闭接收报告可能是合适的。

计算出的复合RTCP数据包传输间隔也应有一个下限,以避免在参与人数较少且流量未按大数定律(law of large numbers)平滑时,数据包突发超过允许带宽。它还能防止报告间隔在网络分区等瞬时中断时变得过小,从而在分区愈合时延迟适应。在应用程序启动时,应在发送第一个复合 RTCP数据包之前设置一个延迟,以便有时间从其他参与方接收RTCP数据包,从而使报告间隔更快地收敛到正确值。此延迟可设置为最小间隔的一半,以便更快地通知新的参与者。固定最小间隔的推荐值为5秒。

实施方案可将最小RTCP 时间间隔调整为与会话带宽参数成反比的较小值,但有以下限制:

1.对于组播会话(multicast sessions),只有活动数据发送方可使用缩减后的最小值来计算复合 RTCP数据包的传输间隔。

2.对于单播会话(unicast sessions),非活动数据发送方的参与者也可以使用减少的值,发送初始复合RTCP数据包前的延迟可以为零。

3.对于所有会话,在计算参与者超时间隔时应使用固定的最小值(见《RFC 3550》第6.3.5节),这样不使用减小值传输RTCP数据包的实现就不会被其他参与者过早超时。

4.以秒为单位的缩减最小值建议值为360 除以 以千位/秒为单位的会话带宽。带宽大于72千比特/秒时,最小值小于5秒。

在《RFC 3550》第6.3节和附录A.7中描述的算法就是为实现本节(RTCP Transmission Interval)所述目标而设计的。它计算发送复合RTCP数据包的间隔时间,以便在各参与方之间分配允许的控制流量带宽。这样,应用程序就能为小型会话提供快速响应,例如,在小型会话中,识别所有参与者非常重要、同时自动适应大型会话。该算法具有以下特点:

1.RTCP数据包之间的计算间隔与组内成员的数量成线性关系。正是这个线性系数使得所有成员的控制流量总和保持不变。

2.RTCP数据包之间的间隔在计算间隔的 [0.5,1.5] 倍范围内随机变化,以避免所有参与者意外同步。加入会话后发送的第一个RTCP数据包的延迟时间也是最小RTCP时间间隔的一半。

3.计算平均复合RTCP 数据包大小的动态估计值,包括所有接收和发送的数据包,以自动适应所携带控制信息量的变化。

4.由于计算出的间隔取决于观察到的小组成员数量,因此当一个新用户加入现有会话或许多用户同时加入一个新会话时,可能会产生不理想的启动效应。这些新用户最初会对群组成员有不正确的估计,因此他们的RTCP传输间隔会太短。如果许多用户同时加入会话,这个问题就会非常严重。为了解决这个问题,《RFC 3550》采用了一种名为 “定时器重新考虑(timer reconsideration) ”的算法。该算法实现了一种简单的后退(back-off)机制,当组规模不断增大时,该机制会使用户推迟 RTCP数据包的传输。

5.当用户以BYE或超时方式离开会话时,群组成员会减少,因此计算出的时间间隔也会缩短。《RFC 3550》采用了一种 “反向重新考虑(reverse reconsideration) ”算法,让成员能更快地缩短他们的时间间隔,以应对群组成员减少的情况。

6.BYE数据包的处理方式与其他RTCP数据包不同。当用户离开一个分组并希望发送BYE数据包时,可以在下一个预定的RTCP数据包之前发送BYE数据包。不过,BYE 的传输遵循一种后退(back-off)算法,以避免在大量用户离开时出现BYE数据包泛洪(floods )。

这种算法可用于允许所有参与者发送信息的会话。在这种情况下,会话带宽参数为:单个发送方带宽乘以参与方数量的乘积,RTCP带宽为该值的 5%。

该算法的运行细节将在后面的章节中给出。《RFC 3550》附录A.7给出了一个实现示例。

七、Maintaining the Number of Session Members

本段内容对应《RFC 3550》的第6.2.1节。根据《RFC 3550》第23页,RTCP数据包间隔的计算取决于对参与会话的站点数量的估计。当听到新的站点时,就会将其添加到计数中,并应在以 SSRC或CSRC标识符为索引的表中为每个站点创建一个条目(见《RFC 3550》第8.2节),以跟踪这些站点。在收到多个携带新SSRC 的数据包(见《RFC 3550》附录 A.1)或收到包含该 SSRC的CNAME的SDES RTCP 数据包之前,新条目可视为无效。当收到带有相应SSRC标识符的RTCP BYE 数据包时,可从表中删除条目,但BYE之后可能会收到一些杂散数据包,导致条目被重新创建。相反,应将条目标记为已收到BYE,然后在适当延迟后删除。

如果在较少的RTCP报告时间间隔内(建议为5个)没有收到RTP或RTCP数据包,则参与者可将另一个站点标记为非活动站点,或在该站点无效时将其删除。这样可以在一定程度上防止数据包丢失。所有站点必须具有相同的乘数值,并且必须计算出大致相同的RTCP报告间隔值,才能使超时正常工作。因此,应针对特定配置文件固定该乘数。

对于有大量参与者的会话,维护一个表来存储所有参与者的SSRC标识符和状态信息可能不切实际。实施方案可以使用SSRC采样来减少存储需求。也可以使用性能类似的其他算法。一个关键的要求是,所考虑的任何算法都不应大大低估分组规模,尽管它可能会高估。

八、RTCP Packet Send and Receive Rules

本段内容对应《RFC 3550》的第6.3节。根据《RFC 3550》第24页,这里概述了如何发送和接收 RTCP数据包时的操作规则。允许在组播环境或多点单播环境中运行的实现必须满足《RFC 3550》第6.2节中的要求。这种实现可以使用本节定义的算法来满足这些要求,也可以使用其他算法,只要它能提供同等或更好的性能。受限于双方单播操作的实现仍应使用RTCP传输间隔的随机化,以避免在同一环境中运行的多实例意外同步,但可以省略《RFC 3550》第6.3.3、6.3.6和 6.3.7节中的 “定时器重新考虑(timer reconsideration) ”和 “反向重新考虑(reverse reconsideration) ”算法。

为了执行这些规则,会话参与者必须保持几种状态:

tp: 上次传输RTCP数据包的时间;

tc: 当前时间;

tn:RTCP数据包的下一个预定传输时间;

pmembers:上次重新计算tn时会话成员的估计数量;

members:对届会成员(session members)人数的最新估计;

senders:会话中发送者数量的最新估计值;

rtcp_bw: 目标RTCP带宽,即此会话的所有成员用于RTCP数据包的总带宽(以每秒八字节为单位)。这将是启动时提供给应用程序的 “会话带宽 ”参数的指定分数。

we_sent: 如果应用程序在上一份RTCP报告发送后又发送了数据,则该标志为真。

avg_rtcp_size: 该参与者发送和接收的所有RTCP数据包的平均复合RTCP数据包大小(以八位字节为单位)。如《RFC 3550》第6.2节所述,该大小包括低层传输和网络协议标头(如UDP和IP)。

initial: 如果应用程序尚未发送RTCP数据包,则该标志为真。

其中许多规则利用了数据包传输之间的 “计算间隔(calculated interval)”。

(一)Computing the RTCP Transmission Interval 

本段内容对应《RFC 3550》的第6.3.1节。根据《RFC 3550》第25页,为保持可扩展性,会话参与者数据包之间的平均间隔应随群组规模的增加而增加。这个间隔称为计算间隔(calculated interval)。它是通过综合上述的一些状态片段得到的。计算间隔T的确定方法如下:

1.如果发送者的数量小于或等于成员(会员)数的 25%,则间隔时间取决于参与者是否为发送者(基于我们发送的数值)。如果参与者是发送者(we_sent为true),常数C将设为RTCP数据包平均大小(avg_rtcp_size)除以25%的RTCP带宽(rtcp_bw),常数n将设为发送者数量。如果 “we_sent ”为非 true,常数C将被设置为RTCP数据包平均大小除以75%的RTCP带宽。常数n设为接收者(成员-发送者)的数量。如果发送方的数量大于25%,则发送方和接收方将一起处理。常数C设为RTCP数据包平均大小除以RTCP总带宽,n设为成员总数。如第《RFC 3550》6.2节所述,RTP配置文件(profile)可以规定,RTCP带宽可以由两个单独的参数(称为S和R)明确定义,分别用于发送方和非发送方的参与者。在这种情况下,25%的分数变为S/(S + R),75%的分数变为R/(S + R)。请注意,如果R为零,发送者的百分比永远不会大于 S/(S + R),因此必须避免除以零。

2.如果参与者尚未发送RTCP数据包(变量initial为true),常数Tmin将被设置为2.5秒,否则将被设置为5秒。

3.确定性计算区间Td设为max(Tmin,n*C)。

4.计算区间T设置为确定性计算区间的0.5至1.5倍之间的一个均匀分布的数字。

5.得出的T值除以 e - 3/2=1.21828 以补偿定时器重新考虑算法(timer reconsideration algorithm)收敛到低于预期平均值的RTCP带宽值这一事实。

这个过程产生的间隔是随机的,但平均而言,至少有25%的RTCP带宽给了发送方,其余的给了接收方。如果发送方占成员总数的成员的四分之一,则该程序将带宽平均分配给所有参与者。平均分配。

(二)Initialization

本段内容对应《RFC 3550》的第6.3.2节。根据《RFC 3550》第26页,加入会话后,参与者将tp 初始化为0,将tc初始化为0,将senders初始化为0,将pmembers初始化为 1,将 members初始化为 1,将 we_sent初始化为false,将 rtcp_bw初始化为指定会话带宽的一部分,将 initial初始化为 true,将 avg_rtcp_size 初始化为应用程序稍后构建的第一个RTCP数据包的可能大小。然后计算出时间间隔T,并将第一个数据包安排在tn = T时间。这意味着设置了一个传输定时器,该定时器在T时间到期。

(三)Receiving an RTP or Non-BYE RTCP Packet

本段内容对应《RFC 3550》的第6.3.3节。根据《RFC 3550》第26页,当从一个SSRC不在成员表(member table)中的参与者接收到RTP或RTCP数据包时,SSRC会被添加到表中,一旦参与者通过《RFC 3550》第6.2.1节所述的验证,成员值就会被更新。当收到来自SSRC不在发送方表中的参与者的RTP数据包时,会将SSRC添加到表中,并更新发送方的值:

avg_rtcp_size = (1/16) * packet size + (15/16) * avg_rtcp_size

其中,数据包大小是指刚刚接收到的RTCP数据包的大小。

(四)Receiving an RTCP BYE Packet

本段内容对应《RFC 3550》的第6.3.4节。根据《RFC 3550》第26页,除《RFC 3550》第6.3.7 节所述要传输RTCP BYE的情况外,如果接收到的数据包是RTCP BYE 数据包,则根据成员表检查SSRC。如果存在,则从表中删除条目并更新成员值。然后根据发送方表检查SSRC。此外,为了使RTCP数据包的传输速率更能适应群组成员的变化,当收到一个BYE数据包,将成员减少到小于pmembers的值时,应执行以下 “反向重新考虑(reverse reconsideration)”算法:

1.tn的值根据以下公式更新:tn = tc + (members/pmembers) * (tn - tc)

2.tp的值根据以下公式更新:tp = tc - (members/pmembers) * (tc - tp)

3.下一个RTCP数据包重新安排在tn时间传输,现在时间提前了。

4.pmembers的值等于 members。

这种算法并不能防止在一个大型会话中,大多数参与者同时离开,但仍有一些参与者留在会话中时,由于过早超时而导致组规模估计值在短时间内错误地降为零。这种情况并不常见,其后果也无伤大雅,因此我们认为这个问题只是次要问题。

(五)Timing Out an SSRC

本段内容对应《RFC 3550》的第6.3.5节。根据《RFC 3550》第27页,每隔一段时间,参与者必须检查是否有其他参与者超时。为此,参与者要计算一个接收者的确定性(不含随机化因子)计算时间间隔Td,即we_sent为false。自时间tc - MTd(M 为超时乘数,默认为 5)起未发送过RTP或 RTCP数据包的任何其他会话成员都会超时。这意味着其SSRC将从成员列表中删除,成员也将更新。对发送方列表也会执行类似的检查。发送方列表中的任何成员,如果在时间tc - 2T之后(最近两个RTCP报告时间间隔内)没有发送过 RTP 数据包,就会从发送方列表中删除,并更新发送方。

如果任何成员超时,则应执行《RFC 3550》第6.3.4节所述的反向重新考虑(reverse reconsideration)算法。参与者必须在每个RTCP传输间隔至少执行一次这种检查。

(六)Expiration of Transmission Timer

本段内容对应《RFC 3550》的第6.3.6节。根据《RFC 3550》第27页,当数据包传输计时器)(packet transmission timer)到期时,参与方执行以下操作:

1.传输间隔T的计算方法如《RFC 3550》第6.3.1节所述,包括随机因子(randomization factor)。

2.如果tp + T小于或等于tc,则传输RTCP数据包。tp设置为tc,然后按照上一步计算另一个T值,tn 设置为tc + T。如果tp + T大于tc,则tn设置为tp + T。传输定时器在tn设置为过期。

3.pmembers设置为members。

如果传输了RTCP数据包,initial的值将设为FALSE。此外,avg_rtcp_size的值也会更新:

avg_rtcp_size = (1/16) * packet_size + (15/16) * avg_rtcp_size

其中,数据包大小(packet_size)是指刚刚传输的RTCP数据包的大小。

(七)Transmitting a BYE Packet

本段内容对应《RFC 3550》的第6.3.7节。根据《RFC 3550》第27页,当一名与会者希望离开会话时,系统会发送BYE数据包通知其他与会者。为了避免许多参与者离开系统时BYE数据包泛滥,如果参与者选择离开时成员数超过50,则必须执行以下算法。该算法取代了members变量的正常作用,改为计算BYE数据包:

1.当参与者决定离开系统时,tp重置为tc,当前时间、member和pmembers初始化为1,initial设置为1,we_sent设置为false,senders设置为0,avg_rtcp_size设置为复合BYE数据包的大小。计算出时间间隔 T。然后将BYE数据包安排在tn = tc + T时间段。

2.每次收到另一个参与者的BYE数据包时,无论该参与者是否存在于成员表(member table)中,成员(members)都会递增 1;使用SSRC采样时,无论BYE SSRC是否包含在采样中,members都会递增1。 收到其他RTCP数据包或RTP数据包时,members不会递增,只有收到BYE数据包时才会递增。同样,avg_rtcp_size只在收到BYE数据包时才会更新。当RTP数据包到达时,发送者(senders)不会更新,而是保持为 0。

3.然后,BYE数据包的传输将遵循上述传输普通RTCP数据包的规则。

这样就可以立即发送BYE数据包,同时控制其总带宽使用量。在最坏的情况下,这可能导致RTCP 控制数据包占用的带宽是正常情况下的两倍(10%)--5% 用于非BYE RTCP数据包,5%用于 BYE。

不想等待上述机制允许发送BYE数据包的参与者可以不发送BYE就离开群组。该参与者最终会被其他群组成员超时。

如果参与者决定离开时,估计的群组成员人数少于 50人,参与者可立即发送BYE数据包。或者,参与者可以选择执行上述BYE返回算法( BYE backoff algorithm)。

在这两种情况下,从未发送过RTP或RTCP数据包的参与者在离开群组时不得发送BYE数据包。

(八)Updating we_sent 

本段内容对应《RFC 3550》的第6.3.8节。根据《RFC 3550》第28页,如果参与者最近发送了一个RTP数据包,we_sent变量中就会包含 “true”,否则就是 “false”。这种判断方法与管理发送方表中列出的其他参与者的机制相同。如果参与者在 we_sent为false时发送了RTP 数据包,它就会将自己添加到发送者表中,并将 we_sent设为true。在发送SR数据包之前,应执行《RFC 3550》第6.3.4节所述的反向重新考虑算法(reverse reconsideration algorithm),以减少延迟。每次发送另一个RTP数据包时,表中都会保留该数据包的发送时间。然后对参与者应用正常的发送者超时算法(sender timeout algorithm)——如果自时间tc - 2T之后没有发送过RTP 数据包,参与者就会从发送者表中删除自己,递减发送者计数( sender count),并将we_sent设为 false。

(九)Allocation of Source Description Bandwidth

本段内容对应《RFC 3550》的第6.3.9节。根据《RFC 3550》第29页,除必选的CNAME项外,《RFC 3550》还定义了几个源描述 (SDES) 项,如NAME(个人姓名)和EMAIL(电子邮件地址)。它还提供了定义新的特定于应用程序的RTCP数据包类型的方法。应用程序在为这些附加信息分配控制带宽时应谨慎,因为这会降低接收报告(reception reports)和CNAME的发送速度,从而影响协议的性能。建议分配给单个参与者的RTCP带宽中用于传输附加信息的部分不超过20%。此外,并不打算在每个应用程序中都包含所有SDES项目。那些被包含的项目应根据其效用分配一部分带宽。建议根据项目的典型长度将百分比静态转换为报告间隔计数,而不是动态估算这些分数。

例如,一个应用程序可能只发送CNAME、NAME和EMAIL,而不发送任何其他内容。NAME的优先级可能比EMAIL高得多,因为NAME会在应用程序的用户界面中持续显示,而EMAIL只有在请求时才会显示。每个RTCP间隔都会发送一个RR数据包和一个包含CNAME项目的SDES数据包。对于以最小间隔运行的小型会话,平均每5秒钟发送一次。每隔第三个间隔(15 秒),SDES数据包中就会多出一个项目。八次中有七次是NAME 项目,每八次(2 分钟)是EMAIL项目。

当多个应用程序通过每个参与者的共同CNAME使用跨应用程序绑定协同运行时,例如在由每个媒体的RTP会话组成的多媒体会议中,附加SDES信息可能只在一个RTP会话中发送。其他会话将只携带CNAME 项目。这种方法尤其适用于分层编码方案的多个会话(见《RFC 3550》第2.4节)。

相关文章:

音视频入门基础:RTCP专题(2)——RTCP协议简介(上)

一、引言 本文对RTCP协议进行简介。在简介之前,请各位先下载RTCP的官方文档《RFC 3550》。《RFC 3550》总共有89页。本文下面所说的“页数”是指在pdf阅读器中显示的页数: 二、RTCP协议简介 本段内容对应《RFC 3550》的第6节。根据《RFC 3550》第17页&…...

oklink js逆向(入口定位)

分析api请求,定位参数 X-Apikey 搜索关键字apikey,发现结果太多 结合搜索结果,搜索关键字 apikey(,只找到5个 断点后定位 可见使用了字符串混淆,所以搜索不到 x-apikey 还可以通过搜索 headers,追踪调用栈的…...

go原子操作和锁的区别是什么?

在Go语言中,原子操作和锁都是用于实现并发编程的同步机制,但它们的工作方式和适用场景有所不同。下面是它们的主要区别: 1. 原子操作(Atomic Operations) 定义:原子操作是一种不可分割的操作,…...

QtConcurrent

以下是 QtConcurrent 的一些常见用法示例&#xff1a; QtConcurrent::run QtConcurrent::run 是最常用的函数&#xff0c;用于在单独的线程中运行一个函数。 运行普通函数 #include <QtConcurrent> #include <QDebug> #include <QThread>void myFunction…...

Git 仓库在内网与 Gitee 间迁移及同步记录

Git 仓库在内网与 Gitee 间迁移及同步记录 在软件开发过程中&#xff0c;常常会遇到需要将代码仓库进行迁移或同步的情况。近期我就碰到了要把 Gitee 代码仓库移植到内网代码仓库&#xff0c;并且后续还得进行同步的需求。这里把整个过程记录下来&#xff0c;方便以后自己参考…...

如何保证mysql和redis的数据一致性

保证 MySQL 和 Redis 的数据一致性是分布式系统中常见的挑战&#xff0c;因为 Redis 作为缓存层&#xff0c;可能存在与底层数据库数据不一致的情况。以下是几种常用的方案及其优缺点对比&#xff1a; 1. 缓存更新策略 (1) Cache-Aside Pattern&#xff08;旁路缓存模式&#…...

Java学习——day23(反射的对象创建与方法调用)

文章目录 1. 使用反射实例化对象1.1 利用无参构造函数创建对象1.2利用带参构造函数创建对象 2.通过反射调用对象方法2.1 调用公共方法2.2 调用私有方法&#xff08;需设置访问权限&#xff09;3. 访问和修改对象的属性3.1 公共属性3.2 私有属性 4. 实践任务4.1工厂类 SimpleFac…...

遇到无法连接香港服务器可能是什么原因导致的呢

遇到无法连接香港服务器的情况时&#xff0c;别急着重启或联系客服&#xff0c;先搞清楚到底是哪里断了链条。问题可能出在服务器本身&#xff0c;也可能是你的本地网络、路由路径、DNS、甚至运营商的“干预”。以下是常见的几个可能原因&#xff0c;建议你可以逐一排查&#x…...

Python----计算机视觉处理(Opencv:道路检测完整版:透视变换,提取车道线,车道线拟合,车道线显示,)

Python----计算机视觉处理&#xff08;Opencv:道路检测之道路透视变换) Python----计算机视觉处理&#xff08;Opencv:道路检测之提取车道线&#xff09; Python----计算机视觉处理&#xff08;Opencv:道路检测之车道线拟合&#xff09; Python----计算机视觉处理&#xff0…...

javaweb自用笔记:Maven分模块设计与开发、Maven继承与聚合、Maven私服

Maven分模块设计与开发 Maven继承与聚合 继承 版本锁定 dependencies引入依赖&#xff0c;dependencyManagement不代表依赖被引入&#xff0c;如果要使用dependencyManagement下的依赖&#xff0c;还需要在dependencies里面定义 聚合 如果没有用聚合&#xff0c;将这个项目打…...

在PyCharm中出现 **全角字符与非英文符号混合输入** 的问题

在PyCharm中出现 全角字符与非英文符号混合输入 的问题&#xff08;如 &#xff11;&#xff12;&#xff14;&#xff13;&#xff14;&#xff15;&#xff44;&#xff46;&#xff53;&#xff04;&#xffe5;&#xff43;&#xff56;&#xff44;&#xff09;&#xff0…...

数字身份DID协议:如何用Solidity编写去中心化身份合约

本文提出基于以太坊的自主主权身份&#xff08;SSI&#xff09;实现方案&#xff0c;通过扩展ERC-734/ERC-735标准构建链上身份核心合约&#xff0c;支持可验证声明、多密钥轮换、属性隐私保护等特性。设计的三层架构体系将身份控制逻辑与数据存储分离&#xff0c;在测试网环境…...

Linux的RPM包管理详解

Linux的RPM包管理详解 引言 RPM&#xff08;Red Hat Package Manager&#xff09;是Linux系统中一种重要的软件包管理工具&#xff0c;它以“.rpm”为扩展名&#xff0c;广泛应用于基于Red Hat的Linux发行版&#xff0c;如CentOS、Fedora、openSUSE等。RPM包不仅简化了软件包…...

其它理论原则

ABC理论 假设&#xff08;Assumption&#xff09;影响行为&#xff08;Behavior&#xff09;&#xff0c;行为最终影响结果&#xff08;Consequence&#xff09;。 如果产品经理认为同事是一个不讲道理的人&#xff0c;那么产品经理在和他交流时就会产生抵触的行为&#xff0c…...

C++中的类和对象(上)

1 类的定义 1.1 类定义的格式 1 class为定义类的关键字&#xff0c;Stack为类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后面分号不能省 略》。类体中内容称为类的成员&#xff1a;类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数…...

LLaMA-Factory 数据集成从入门到精通

一、框架概述 LLaMA-Factory 框架通过Alpaca/Sharegpt双格式体系实现多任务适配&#xff0c;其中Alpaca专注结构化指令微调&#xff08;含SFT/DPO/预训练&#xff09;&#xff0c;Sharegpt支持多角色对话及多模态数据集成。核心配置依托 dataset_info.json 实现数据源映射、格…...

高级:JVM面试题深度剖析

一、引言 在Java技术面试中&#xff0c;JVM&#xff08;Java虚拟机&#xff09;相关知识是考察重点之一。深入理解JVM的内存模型、垃圾回收机制、类加载机制等&#xff0c;不仅能帮助开发者优化Java应用性能&#xff0c;还能在面试中展现深厚的技术功底。本文将针对这些高频知…...

Spring MVC 中 @ResponseBody 注解深度使用教程

一、注解核心作用 ResponseBody 是 Spring MVC 中处理 响应体内容 的核心注解&#xff0c;主要功能&#xff1a; 跳过视图解析器&#xff1a;直接返回数据而非视图名称自动数据转换&#xff1a;根据返回值类型自动转换响应格式&#xff08;JSON/XML/纯文本&#xff09;RESTfu…...

数据结构第一轮复习--第七章查找(包含课程代码)

基于数组实现顺序查找代码 //顺序查找的实现 typedef struct{ //查找表的数据结构&#xff08;顺序表&#xff09; ElemType *elem; //指向开辟的动态数组基址 &#xff08;起始地址&#xff09; int TableLen; //表的长度 }SSTable; //顺序查找 int Search_Seq(SSTable ST…...

Springboot JPA 集成ShardingSphere

Spring Boot集成JPA与ShardingSphere可通过以下步骤实现分库分表功能&#xff0c;需重点关注依赖配置、分片规则定义及JPA适配问题&#xff1a; 一、依赖配置 1‌. 引入核心依赖‌ 在pom.xml中添加ShardingSphere和JPA相关依赖&#xff1a; <!-- ShardingSphere JDBC --&…...

详细介绍javaspringboot操控redis的高级特性1. 事务支持2. 发布/订阅3. Pipeline批量操作

Spring Boot 对 Redis 的操作提供了丰富的高级特性&#xff0c;以下是对事务支持、发布 / 订阅、Pipeline 批量操作的详细介绍&#xff1a; 事务支持 原理&#xff1a;Redis 事务是一个单独的隔离操作&#xff0c;它可以包含多个命令&#xff0c;这些命令要么全部执行&#x…...

第一次3D打印,一个简单的小方块(Rhino)

一、建模 打开犀牛&#xff0c;我们选择立方体 我们点击上册的中心点 输入0&#xff0c;然后回车0 而后我们输长度&#xff1a;10&#xff0c;回车确认 同样的&#xff0c;宽度10 高度同样是10 回车确认后&#xff0c;我们得到一个正方形 二、导出模型 我们选择文件—>保存…...

数据分享:汽车测评数据

说明&#xff1a;如需数据可以直接到文章最后关注获取。 1.数据背景 Car Evaluation汽车测评数据集是一个经典的机器学习数据集&#xff0c;最初由 Marko Bohanec 和 Blaz Zupan 创建&#xff0c;并在 1997 年发表于论文 "Classifier learning from examples: Common …...

硬盘分区格式之GPT(GUID Partition Table)笔记250406

硬盘分区格式之GPT&#xff08;GUID Partition Table&#xff09;笔记250406 GPT&#xff08;GUID Partition Table&#xff09;硬盘分区格式详解 GPT&#xff08;GUID Partition Table&#xff09;是替代传统 MBR 的现代分区方案&#xff0c;专为 UEFI&#xff08;统一可扩展固…...

辉视智慧医院:以科技温度 重塑医疗未来新生态

大家是否想过&#xff0c;医院里的广播对讲系统也能变身‘智慧管家’&#xff1f;今天带您走进辉视智慧医院&#xff0c;看看他们如何用四大黑科技&#xff0c;让医患沟通更暖心、更高效&#xff01; 一、物联网技术&#xff1a;医疗设备‘开口说话’&#xff0c;广播系统秒变‘…...

Google 发布 Sec-Gemini v1:用 AI 重塑网络安全防御格局?

在网络威胁日益复杂化、自动化程度不断提高的今天&#xff0c;防御方常常感到力不从心。为了扭转这一局面&#xff0c;Google 近日迈出了重要一步&#xff0c;宣布推出专为网络安全领域量身打造的实验性 AI 模型——Sec-Gemini v1。该模型由 Google 内部的 Sec-Gemini 团队成员…...

Android 使用ninja加速编译的方法

ninja的简介 随着Android版本的更迭&#xff0c;makefile体系逐渐增多&#xff0c;导致make单编模块的时间越来越长&#xff0c;每次都需要半个小时甚至更长时间&#xff0c;其原因为每次make都会重新加载所有mk文件&#xff0c;再生成ninja编译&#xff0c;此完整过程十分耗时…...

windterm终端软件使用

windterm终端软件使用 下载安装包&#xff1a;https://github.com/kingToolbox/WindTerm/releases ssh连接&#xff1a; 可以复用vscode连接ssh信息 onekey 相当于服务器主机的用户名和密码 点击配置标签如Linux&#xff0c;输入用户名如root, identity file指定本地公钥&a…...

《操作系统真象还原》第六章——完善内核

文章目录 [toc]前言调用约定和混合编程调用约定混合编程 实现打印函数print.S显卡的端口控制实现单个字符打印put_char定义数据类型put_char编码修改内核main.c验证put_char 实现字符串打印put_str 结语 前言 学完上一章后&#xff0c;我们已经完成了一个操作系统最基本的三个…...

上海餐饮市场数据分析与可视化

上海作为中国的经济中心和国际化大都市,其餐饮市场具有高度的多样性和竞争性。随着消费者需求的不断变化,餐饮行业的从业者和投资者需要深入了解市场现状和趋势,以便制定更有效的商业策略。本文将通过数据分析和可视化技术,深入探讨上海餐饮市场的现状和趋势,为餐饮从业者…...

不花钱也能玩GPT-4o,国内可用

家人们&#xff01;最近GPT-4o生图功能真的离谱到不真实&#xff0c;各种吉卜力、宫崎骏、3D风格等刷爆小红书。 由于只有GPT官网&#xff0c;只有Plus用户才能用&#xff0c;很多小伙伴们都没有机会体验过GPT&#xff0c;本期就分享一个国内也能直接玩的方法。 第一步&#x…...

ResNet改进(22):提升特征选择能力的卷积神经网络SKNet

在计算机视觉领域,残差网络(ResNet)一直是图像分类任务中的经典架构。本文将介绍一种改进版的ResNet18,它融合了选择性核(SK)机制,能够自适应地调整不同感受野的特征权重,从而提升模型性能。下面我们将详细解析这个实现代码。 一、代码概述 这个Python脚本实现了一个带有S…...

实战代码:esp32-cam按钮控制手机拍照V1.0

#include <WiFi.h> #include <HTTPClient.h> // WiFi设置 const char* ssid “MIFI-020806-2.4G”; const char* password “12345678”; // 静态IP配置 IPAddress staticIP(192, 168, 1, 32); // 设置为固定IP IPAddress gateway(192, 168, 1, 1); // 网关地址…...

Base64是密码吗?编码与加密的本质区别

&#xff08;本文完全由deepseek生成&#xff0c;特此声明&#xff01;&#xff09;‌ 引言&#xff1a;一个让开发者“翻车”的经典误区‌ 我们常看到类似这样的提问&#xff1a; “我用Base64加密了用户的密码&#xff0c;为什么还是被黑客破解了&#xff1f;” “Base64解…...

原理图输出网表及调入

一、输出网表操作步骤 &#xff08;1&#xff09;选中.dsn文件&#xff0c;选者N或进入tools下拉列表选择Creat Netlists &#xff08;2&#xff09;导出网表后的文件 二、网表的导入 &#xff08;1&#xff09;执行菜单命令“File-Import-Logic/netlist”&#xff0c;将原理…...

C++ 模板的应用——智能指针、STL库

#include "head.h" #include <stdio.h> using namespace std;void registerUser(vector<string>& number,vector<string>& passwd){string username;string Passwd;cout << "请输入账号:" << endl;cin >> use…...

基于层次建模与交叉注意力融合的医学视觉问答系统(HiCA-VQA)详解

论文地址:https://arxiv.org/pdf/2504.03135 一、论文结构概述 这篇论文提出了一种针对医学视觉问答(Medical Visual Question Answering, Med-VQA)的层次化建模框架 ​HiCA-VQA,旨在解决现有方法在层次化语义建模和跨模态融合上的不足。以下是论文的核心结构: ​引言 介…...

比较与分析敏捷开发方法:XP、Scrum、FDD等的特点与适用场景

目录 前言1. 极限编程 (XP)1.1 极限编程的核心特点1.2 极限编程的适用场景 2. Scrum2.1 Scrum的核心特点2.2 Scrum的适用场景 3. 水晶方法 (Crystal)3.1 水晶方法的核心特点3.2 水晶方法的适用场景 4. 特征驱动开发 (FDD)4.1 特征驱动开发的核心特点4.2 特征驱动开发的适用场景…...

ICMP 协议深度解析

ICMP 协议深度解析 一、协议定位与核心作用 ICMP&#xff08;互联网控制报文协议&#xff09;是IP协议体系的"哨兵系统"&#xff0c;专用于网络状态监控与异常反馈。其核心价值体现在&#xff1a; 轻量级控制&#xff1a;仅传递关键状态信息&#xff0c;不承载业务…...

C语言基础20

内容提要 预处理 库文件 预处理 C语言编译步骤 预处理 编译 汇编 链接 什么是预处理 预处理就是在源文件&#xff08;.c文件&#xff09;编译之前&#xff0c;所进行的一部分预备操作&#xff0c;这部分操作是由预处理程序自动完成。当源文件在编译时&#xff0c;编译…...

conda常用命令

要查看使用conda创建的虚拟环境&#xff0c;可以按照以下步骤操作&#xff1a; 打开终端或命令行工具&#xff1a;确保你已经打开了终端或命令行界面&#xff0c;以便输入conda命令。 输入命令查看环境列表&#xff1a; 使用以下任一命令查看conda创建的虚拟环境&#xff1a…...

Ubunut18.04 离线安装MySQL 5.7.35

一、环境准备 1.1 官方下载MySQL5.7.35 完整包 1.2 上传包 & 解压 上传包名称是&#xff1a;mysql-server_5.7.35-1ubuntu18.04_amd64.deb-bundle.tar # 切换到上传目录 cd /home/MySQL # 解压&#xff1a; tar -xvf mysql-server_5.7.35-1ubuntu18.04_amd64.deb-bundle…...

地图与图层操作

地图文档本质上就是存储在磁盘上的地图&#xff0c;包括地理数据、图名、图例等一系列要素&#xff0c;当完成地图制作、图层要素标注及符号显示设置后&#xff0c;可以将其作为图层文件保存到磁盘中&#xff0c;在一个图层文件中&#xff0c;包括了定义如何在地图上描述地理数…...

红宝书第三十一讲:通俗易懂的包管理器指南:npm 与 Yarn

红宝书第三十一讲&#xff1a;通俗易懂的包管理器指南&#xff1a;npm 与 Yarn 资料取自《JavaScript高级程序设计&#xff08;第5版&#xff09;》。 查看总目录&#xff1a;红宝书学习大纲 一、基础概念 包管理器&#xff1a;帮你自动下载和管理第三方代码库&#xff08;如…...

李建忠:智能体正将互联网从信息网络重构为行动网络

引言 模型正在从训练为主转换为推理为主的新范式&#xff0c;智能体正将互联网从信息网络重构为行动网络&#xff0c;我们正处在从人类使用互联网到 AI 代理使用互联网的转折点。这不是未来&#xff0c;而是此刻已经发生的颠覆。 3 月 22 日&#xff0c;在腾讯云架构师技术同…...

瑞芯微AI处理器详解

瑞芯微&#xff08;Rockchip&#xff09;的芯片产品线覆盖从低功耗MCU到高性能AIoT处理器&#xff0c;以下是其主流芯片系列及RK3568的市场定位分析&#xff1a; 一、瑞芯微主要芯片系列 旗舰级 RK3588&#xff1a;12nm工艺&#xff0c;4A764A55&#xff0c;6TOPS NPU&#xff…...

Compose Multiplatform+Kotlin Multiplatfrom 第五弹跨平台

截图功能 Compose MultiplatformKotlin Multiplatfrom下实现桌面端的截图功能&#xff0c;起码搞了两星期&#xff0c;最后终于做出来了&#xff0c;操作都很流畅&#xff0c;截取的文件大小也正常&#xff0c;可参考支持讨论&#xff01; 功能效果 代码实现 //在jvmMain下创…...

linux安装ollama

俩种方式都可 一、linux通过docker安装ollama镜像 1.下载安装ollama镜像 # 安装 Docker sudo yum install docker sudo systemctl start docker#docker查看所有容器 docker ps -a # 查看所有容器# docker查看指定容器 docker ps -a |grep ollama# 创建模型存储目录&#xff…...

113. 在 Vue 3 中使用 OpenLayers 实现鼠标移动显示坐标信息

✨ 写在前面 在地图类项目开发中&#xff0c;一个常见需求就是&#xff1a;实时获取用户鼠标在地图上的经纬度坐标&#xff0c;并展示在地图上。 本文将通过一个简单的案例&#xff0c;手把手带大家在 Vue 3 项目中集成 OpenLayers 地图库&#xff0c;并实现以下功能&#xf…...

跳跃游戏的最优解法——贪心算法的智慧与实践

跳跃游戏的最优解法——贪心算法的智慧与实践 跳跃游戏是一类经典的算法题&#xff0c;既有趣又充满挑战&#xff0c;不仅能锻炼思维能力&#xff0c;还能直观展现贪心算法的核心思想。今天&#xff0c;我们从题目入手&#xff0c;拆解贪心算法的原理&#xff0c;用通俗易懂的…...