webrtc中的带宽自适应算法
转自:http://www.xuebuyuan.com/1248366.html
webrtc中的带宽自适应算法分为两种:
1, 发端带宽控制, 原理是由rtcp中的丢包统计来动态的增加或减少带宽,在减少带宽时使用TFRC算法来增加平滑度。
2, 收端带宽估算, 原理是并由收到rtp数据,估出带宽; 用卡尔曼滤波,对每一帧的发送时间和接收时间进行分析, 从而得出网络带宽利用情况,修正估出的带宽。
两种算法相辅相成, 收端将估算的带宽发送给发端, 发端结合收到的带宽以及丢包率,调整发送的带宽。
下面具体分析两种算法:

2, 接收端带宽估算算法分析
结合文档http://tools.ietf.org/html/draft-alvestrand-rtcweb-congestion-02以及源码webrtc/modules/remote_bitrate_estimator/overuse_detector.cc进行分析
带宽估算模型: d(i) = dL(i) / c + w(i) d(i)两帧数据的网络传输时间差,dL(i)两帧数据的大小差, c为网络传输能力, w(i)是我们关注的重点, 它主要由三个因素决定:发送速率, 网络路由能力, 以及网络传输能力。w(i)符合高斯分布, 有如下结论:当w(i)增加是,占用过多带宽(over-using);当w(i)减少时,占用较少带宽(under-using);为0时,用到恰好的带宽。所以,只要我们能计算出w(i),即能判断目前的网络使用情况,从而增加或减少发送的速率。
算法原理:即应用kalman-filters
theta_hat(i) = [1/C_hat(i) m_hat(i)]^T // i时间点的状态由C, m共同表示,theta_hat(i)即此时的估算值
z(i) = d(i) - h_bar(i)^T * theta_hat(i-1) //d(i)为测试值,可以很容易计算出, 后面的可以认为是d(i-1)的估算值, 因此z(i)就是d(i)的偏差,即residual
theta_hat(i) = theta_hat(i-1) + z(i) * k_bar(i) //好了,这个就是我们要的结果,关键是k值的选取,下面两个公式即是取k值的,具体推导见后继博文。
E(i-1) * h_bar(i)
k_bar(i) = --------------------------------------------
var_v_hat + h_bar(i)^T * E(i-1) * h_bar(i)
E(i) = (I - K_bar(i) * h_bar(i)^T) * E(i-1) + Q(i) // h_bar(i)由帧的数据包大小算出
由此可见,我们只需要知道当前帧的长度,发送时间,接收时间以及前一帧的状态,就可以计算出网络使用情况。
接下来具体看一下代码:
- void OveruseDetector::UpdateKalman(int64_t t_delta,
- double ts_delta,
- uint32_t frame_size,
- uint32_t prev_frame_size) {
- const double min_frame_period = UpdateMinFramePeriod(ts_delta);
- const double drift = CurrentDrift();
- // Compensate for drift
- const double t_ts_delta = t_delta - ts_delta / drift; //即d(i)
- double fs_delta = static_cast<double>(frame_size) - prev_frame_size;
- // Update the Kalman filter
- const double scale_factor = min_frame_period / (1000.0 / 30.0);
- E_[0][0] += process_noise_[0] * scale_factor;
- E_[1][1] += process_noise_[1] * scale_factor;
- if ((hypothesis_ == kBwOverusing && offset_ < prev_offset_) ||
- (hypothesis_ == kBwUnderusing && offset_ > prev_offset_)) {
- E_[1][1] += 10 * process_noise_[1] * scale_factor;
- }
- const double h[2] = {fs_delta, 1.0}; //即h_bar
- const double Eh[2] = {E_[0][0]*h[0] + E_[0][1]*h[1],
- E_[1][0]*h[0] + E_[1][1]*h[1]};
- const double residual = t_ts_delta - slope_*h[0] - offset_; //即z(i), slope为1/C
- const bool stable_state =
- (BWE_MIN(num_of_deltas_, 60) * fabsf(offset_) < threshold_);
- // We try to filter out very late frames. For instance periodic key
- // frames doesn't fit the Gaussian model well.
- if (fabsf(residual) < 3 * sqrt(var_noise_)) {
- UpdateNoiseEstimate(residual, min_frame_period, stable_state);
- } else {
- UpdateNoiseEstimate(3 * sqrt(var_noise_), min_frame_period, stable_state);
- }
- const double denom = var_noise_ + h[0]*Eh[0] + h[1]*Eh[1];
- const double K[2] = {Eh[0] / denom,
- Eh[1] / denom}; //即k_bar
- const double IKh[2][2] = {{1.0 - K[0]*h[0], -K[0]*h[1]},
- {-K[1]*h[0], 1.0 - K[1]*h[1]}};
- const double e00 = E_[0][0];
- const double e01 = E_[0][1];
- // Update state
- E_[0][0] = e00 * IKh[0][0] + E_[1][0] * IKh[0][1];
- E_[0][1] = e01 * IKh[0][0] + E_[1][1] * IKh[0][1];
- E_[1][0] = e00 * IKh[1][0] + E_[1][0] * IKh[1][1];
- E_[1][1] = e01 * IKh[1][0] + E_[1][1] * IKh[1][1];
- // Covariance matrix, must be positive semi-definite
- assert(E_[0][0] + E_[1][1] >= 0 &&
- E_[0][0] * E_[1][1] - E_[0][1] * E_[1][0] >= 0 &&
- E_[0][0] >= 0);
- slope_ = slope_ + K[0] * residual; //1/C
- prev_offset_ = offset_;
- offset_ = offset_ + K[1] * residual; //theta_hat(i)
- Detect(ts_delta);
- }
- BandwidthUsage OveruseDetector::Detect(double ts_delta) {
- if (num_of_deltas_ < 2) {
- return kBwNormal;
- }
- const double T = BWE_MIN(num_of_deltas_, 60) * offset_; //即gamma_1
- if (fabsf(T) > threshold_) {
- if (offset_ > 0) {
- if (time_over_using_ == -1) {
- // Initialize the timer. Assume that we've been
- // over-using half of the time since the previous
- // sample.
- time_over_using_ = ts_delta / 2;
- } else {
- // Increment timer
- time_over_using_ += ts_delta;
- }
- over_use_counter_++;
- if (time_over_using_ > kOverUsingTimeThreshold //kOverUsingTimeThreshold是gamma_2, gamama_3=1
- && over_use_counter_ > 1) {
- if (offset_ >= prev_offset_) {
- time_over_using_ = 0;
- over_use_counter_ = 0;
- hypothesis_ = kBwOverusing;
- }
- }
- } else {
- time_over_using_ = -1;
- over_use_counter_ = 0;
- hypothesis_ = kBwUnderusing;
- }
- } else {
- time_over_using_ = -1;
- over_use_counter_ = 0;
- hypothesis_ = kBwNormal;
- }
- return hypothesis_;
- }
参考文档:
webrtc中的带宽自适应算法的更多相关文章
- Android IOS WebRTC 音视频开发总结(五五)-- 音视频通讯中的抗丢包与带宽自适应原理
本文主要分析webrtc中的抗丢包与带宽自适应原理,文章来自博客园RTC.Blacker,欢迎关注微信公众号blacker,更多详见www.rtc.help 文章内容主要来自中国电信北京研究院丁博士在 ...
- WebRTC中的NetEQ
NetEQ使得WebRTC语音引擎能够快速且高解析度地适应不断变化的网络环境,确保了音质优美且缓冲延迟最小,其集成了自适应抖动控制以及丢包隐藏算法. WebRTC和NetEQ概述 WebRTC Web ...
- ULPFEC在WebRTC中的实现[转载]
一.WebRTC对抗网络丢包的两种手段 丢包重传(NACK)和前向纠错(FEC).FEC是一种前向纠错技术,发送端将负载数据加上一定的冗余纠错码一起发送,接收端根据接收到的纠错码对数据进行差错 ...
- Android IOS WebRTC 音视频开发总结(八十六)-- WebRTC中RTP/RTCP协议实现分析
本文主要介绍WebRTC中的RTP/RTCP协议,作者:weizhenwei ,文章最早发表在编风网,微信ID:befoio 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID ...
- 陕西中际现代:基于自适应算法的PLC滴灌控制系统
基于自适应算法的PLC滴灌控制系统 陕西中际现代包装科技有限公司滴灌部 1.介绍 水资源正在成为一种珍贵的资源.城镇的市民使用成千上万立方的水来浇灌花园和绿地.他们依赖于使用固定灌溉计划的控制器.而这 ...
- Max-Min Fairness带宽分配算法
近期再写一个网络仿真器,里面參考了Max-MinFairness算法,这是一种比較理想.公平的带宽分配算法.其思路主要例如以下:首先是算法的准备,考察某一时刻的网络中全部的flow,因为每条flow都 ...
- webRTC中语音降噪模块ANS细节详解(一)
ANS(adaptive noise suppression) 是webRTC中音频相关的核心模块之一,为众多公司所使用.从2015年开始,我在几个产品中使用了webRTC的3A(AEC/ANS/AG ...
- webRTC中语音降噪模块ANS细节详解(二)
上篇(webRTC中语音降噪模块ANS细节详解(一))讲了维纳滤波的基本原理.本篇先给出webRTC中ANS的基本处理过程,然后讲其中两步(即时域转频域和频域转时域)中的一些处理细节. ANS的基本处 ...
- webRTC中语音降噪模块ANS细节详解(三)
上篇(webRTC中语音降噪模块ANS细节详解(二))讲了ANS的处理流程和语音在时域和频域的相互转换.本篇开始讲语音降噪的核心部分,首先讲噪声的初始估计以及基于估计出来的噪声算先验信噪比和后验信噪比 ...
随机推荐
- VNC server grey screen under ubuntu 14.04
nstall these packages: apt-get install gnome-panel gnome-settings-daemon metacity nautilus gnome-ter ...
- python程序打包成.exe----pyinstaller工具
1. 环境 windows 2. 安装 准备文件:PyWin32 or pypiwin32 运行如下安装命令: pip install pyinstaller==3.0 不要使用3.2版本,编译完成 ...
- 基于隐马尔科夫模型(HMM)的地图匹配(Map-Matching)算法
文章目录 1. 1. 摘要 2. 2. Map-Matching(MM)问题 3. 3. 隐马尔科夫模型(HMM) 3.1. 3.1. HMM简述 3.2. 3.2. 基于HMM的Map-Matchi ...
- pl/sql中having的用法
HAVING的作用: 因为where关键字无法与聚集函数一起使用,HAVING可以和聚集函数一起使用 HAVING的语法: SELECT column_name, aggregate_function ...
- Effective C++ -----条款42:了解typename的双重意义
声明template参数时,前缀关键字class和typename可互换. 请使用关键字typename标识嵌套从属类型名称:但不得在base class lists(基类列)或member init ...
- c++从文件中读取特定字符串问题的总结
1.每次从文件中读出一行作为一个字符串 可以用ifstream()函数来打开一个文件,然后用while加getline()函数即可每次读一行文件,直到文件结束 #include<unistd.h ...
- 【python】类中的self
在python的类中,经常会写self,代表对象自己.如下例: #coding=utf-8 class Foo: def __init__(self, name): self.name = name ...
- struts 拦截器 Interceptor
拦截器是AOP中的概念,它本身是一段代码,可以通过定义“织入点”,来指定拦截器的代码在“织入点”的前后执行,从而起到拦截的作用.正如上面 Struts2的Reference中讲述的,Stru ...
- yii php 图片上传与生成缩略图
今天需要做图片上传与生成缩略图的功能,把代码进行记录如下: html 视图 ($pic_action_url = $this->createAbsoluteUrl('h ...
- 单击双击手势(UITapGestureRecognizer)
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typica ...