前言
- 搞webrtc很多年了,钱没赚到,恶心了那么久,现在想想还不如当初不入坑了,webrtc不单单难在某一个算法,而且难在对整个体系的把控,要把每个策略作用都发挥到最大,webrtc源码过于庞大,费力不讨好,建议新手改行。
- 还不如学学怎么装逼和扯皮,想当年在某cloud搞流媒体,组内一个android毕业生,天天装逼,天天扯皮,从一开始的最低级别,短短两年升到组内最高级别,深深让我体会到靠逼做开发的威力,边装逼边写代码,写代码是为了装逼服务,组内其他成员个个都是影帝,说话又好听,当然,还要遇到一个脑子进水的草包组长。虽然最后小组都搞解散了,但是个个都特别开心,因为有补偿。工作那么久第一次遇到那么奇葩的脑残组
慢启动优化
在webrtc启动阶段,第一个ack时钟的是由探测的策略来产生,这时GCC通过探测来进行码率评估,类型tcp的慢启动:
探测计划启动的滞后
-
慢启动阶段 视频到达pacer比音频慢了一秒,所以,慢启动阶段探测计划创建后,即便有音频数据传递到pacer了,但是由于音频的编码长度为160个字节,甚至85个字节
所以 条件不成立:packet_size >= std::min(RecommendedMinProbeSize(), kMinProbePacketSize) 导致探测无法在只有音频数据的情况下启动。 -
过了一秒后有视频数据后才满足 packet_size 900 >= kMinProbePacketSize 200 才会启动探测计划,导致慢启动阶段的探测滞后,但是没出现探测超时,因为在1秒内会连续创建多个探测计划
-
系统启动后,探测计划启动的太慢 过了两秒后才启动探测 优化如下:
-
1.kMinProbePacketSize 改成 100 可以让探测计划在音频数据来到的时候立刻启动:probing_state_ = kActive
-
2.或者提前启动视频采集,
-
3.或者改成 OnIncomingPacket(std::unique_ptr packet),把字节长度的判断改成判断音视频帧类型,有音频帧就启动probe模块
remb报文对探测的干扰
-
慢启动阶段等待探测结果时state_ == State::kWaitingForProbingResult,接收到remb的报文会影响 current_target_ 的大小,从而触发创建新的探测计划
-
bitrate_bps > min_bitrate_to_probe_further_bps_ 当 remb码率大于 min_bitrate_to_probe_further_bps_时会触发重新探测,本来会以上一个探测码率的2倍作为下一个探测码率,结果现在以remb码率作为下一个探测码率
-
可以禁用 remb的报文 ,或者使能 packet_feedback_only_
rtx 模式的启用 默认使用非rtx模式
-
padding数据生成有两种做法:
-
- rtx 模式:如果启用RTX, WebRTC会从历史发送的packet中取一包数据,把类型改为padding,直到请求的padding_size用尽,并且使用RTX通道专用的序列号序列 问题在于接收端能从这种数据包中恢复媒体数据吗
-
- 非rtx 模式:生成新的RTP Padding包,长度范围:50 - 224字节,超过224分段发,通常224字节满额发送,原因如下
void RtpVideoSender::ConfigureSsrcs() {
for (const RtpStreamSender& stream : rtp_streams_) {
stream.rtp_rtcp->SetRtxSendStatus(kRtxRetransmitted | kRtxRedundantPayloads);
}
}
1.stream.rtp_rtcp->SetRtxSendStatus(kRtxRetransmitted | kRtxRedundantPayloads); 现在是非rtx模式,
改成 stream.rtp_rtcp->SetRtxSendStatus(kRtxRedundantPayloads); 就可以启动rtx模式,不知道接收端效果如何
2.启动rtx模式后, packet_history_ 不为空的时候才使用rtx模式,否则使用非rtx模式
std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetPayloadPaddingPacket(rtc::FunctionView<std::unique_ptr<RtpPacketToSend>(const RtpPacketToSend&)> encapsulate) {
StoredPacket* best_packet = nullptr;
if (enable_padding_prio_ && !padding_priority_.empty()) {
auto best_packet_it = padding_priority_.begin();
best_packet = *best_packet_it;
} else if (!enable_padding_prio_ && !packet_history_.empty()) { // packet_history_ 不为空的时候才使用rtx模式,否则使用非rtx模式
for (auto it = packet_history_.rbegin(); it != packet_history_.rend();
++it) {
if (it->packet_ != nullptr) {
best_packet = &(*it);
break;
}
}
}
}