¿Cuánto ancho de banda requiere un servidor webrtc?
1. Control del ancho de banda del extremo de origen. El principio es aumentar o disminuir dinámicamente el ancho de banda a través de estadísticas de pérdida de paquetes en rtp. Cuando se reduce el ancho de banda, el algoritmo TFRC es. Se utiliza para aumentar la suavidad.
2. El principio de estimación del ancho de banda en el extremo receptor es estimar el ancho de banda a partir de los datos rtcp recibidos; utilizar el filtrado de Kalman para analizar el tiempo de envío y recepción de cada cuadro, a fin de obtener el ancho de banda de la red; utilización, corrija el ancho de banda estimado.
Estos dos algoritmos se complementan entre sí. El receptor envía el ancho de banda estimado al remitente y el remitente ajusta el ancho de banda de envío en función del ancho de banda recibido y la tasa de pérdida de paquetes.
A continuación se analizarán los dos algoritmos:
2. Análisis del algoritmo de estimación del ancho de banda en el lado del receptor
Combinado con el documento http://tools. .ietf/html/draft-alvestrand-rtcweb-congestion-02 y código fuente webrtc/modules/remote_bitrate_estimator/overuse_detector.cc para análisis
Modelo de estimación de ancho de banda: d(i) = dL(i) / c + w (i) d(i) La diferencia en el tiempo de transmisión de la red entre dos tramas de datos, dL(i) La diferencia de tamaño entre dos tramas de datos, c es la capacidad de transmisión de la red, w(i) w(i ) es nuestro enfoque, determinado principalmente por la velocidad de envío, la capacidad de enrutamiento de la red y la capacidad de transmisión de la red están determinadas por tres factores w (i) se ajusta a la distribución gaussiana. La conclusión es: cuando w (i) aumenta, el ancho de banda se utiliza en exceso; cuando w (i) disminuye, el ancho de banda está infrautilizado; cuando w (i) es cero, el uso del ancho de banda es correcto. Por lo tanto, siempre que podamos calcular w (i), podemos determinar la red actual. uso y aumentar o disminuir la tasa de envío
Algoritmo: Filtro de Kalman
theta_hat(i) = [1/C_hat(i) m_hat(i)]^T // El. el estado del i-ésimo punto de tiempo está representado por C, m****, theta_hat(i) es el valor estimado en este momento
z(i) = d(i) - h_bar(i )^T*.bar(i)^T*θ_hat(i-1)//d(i) es el valor de prueba, que es fácil de calcular. Este último puede considerarse como el valor estimado de d(i-1). ), entonces z(i) es la desviación de d(i), es decir, el residual.
theta_hat(i) = theta_hat(i-1) + z( i) * k_ bar(i) // Bien, este es el resultado que queremos. La clave está en la selección del valor k, de la siguiente manera Las dos fórmulas son la derivación específica del valor k, consulte la siguiente publicación del blog <. /p>
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) se calcula en función del tamaño del paquete de el fotograma
Se puede ver que solo necesitamos conocer la duración del fotograma actual, el tiempo de envío, el tiempo de recepción y el estado del fotograma anterior. Puede calcular el uso de la red.
A continuación, echemos un vistazo más de cerca al código:
[cpp] ver
plaincopy
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();
// Compensar la deriva
const double t_ts_delta = t_delta - ts_delta / drift; (i) p>
double fs_delta = static_cast
// Actualizar filtro de Kalman
const double scale_factor = min_frame_period / (1000.0 / 30.0.0);
E_[0][0] += ruido_proceso_[0] * factor_escala
E_[1][1] += ruido_proceso_[1] * scale_factor;
if ((hipótesis_ == kBwOverusing &
if ((hipótesis_ == kBwOverusing & & offset_ < prev_offset_) |
(hipótesis_ == kBwUnderusing && offset_ > prev_ offset_)){
E_[1][1] += 10 * process_noise_[1] * scale_factor
}
const; double h[ 2] = {fs_delta, 1.0}; //es decir
Constante double Eh[2] = {E_[0][0]*h[0] + E_[0][1] *h[ 1],
E_[1][0]*h[0] + E_[1][1]*h[1]}
Residual doble constante; = t_ts_delta - pendiente_*h[0] - offset_; //i. Por ejemplo, z(i), la pendiente es 1/C
const bool stable_state =
(BWE_MIN (num_of_deltas_, 60) * fabsf(offset_) < umbral_);
// Intentamos filtrar fotogramas muy tardíos. Por ejemplo, los fotogramas clave periódicos
// no se ajustan al modelo gaussiano.
if (fabsf(residual) < 3 * sqrt(var_noise_)){
UpdateNoiseEstimate(residual, min_frame_period, stable_state) else { ); p>
p>
UpdateNoiseEstimate(3 * sqrt(var_noise_), min_frame_period, stable_state);
}
Doble denominación constante = var_noise_ + h[0]* Eh[0] + h[1]*Eh[1];
Constante doble K[2] = {Eh[0] / denom,
Eh[1] / denom }; //es decir, 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]}};
Constante doble e00 = E_[0][0]
Constante doble e01 = E_[0][1]
// Estado de actualización
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]
// Matriz de varianza de asociación, debe ser una matriz semifinita positiva
afirmar(E_[0][0] + E_[1][1] >= 0 && amp;
E_[0][ 0] * E_[1][1] - E_[0][1] * E_[1][0] >= 0 &&
E_[0] [0] >= 0);
pendiente_ = pendiente_ + K[0] * residual; //1/C
prev_offset_ = offset_
offset_ = offset_ + K [1] * residual; // theta_hat(i)
Detect(ts_delta
}
[cpp] vista
copia simple
Uso de ancho de banda OveruseDetector::Detect(double ts_delta) {
if (num_of_deltas_ < 2) {
return kBwNormal;
const double T = BWE_MIN(num_of_deltas_, 60) * offset_; //es decir, gamma_1
if (fabsf(T) > umbral_) {
if (offset_ > 0) {
if (time_over_using_ ==
-1) {
// Inicializa el temporizador. Digamos que hemos comprometido demasiado
// la mitad del tiempo desde la última
/ muestra.
// Uso excesivo de temporizadores.
/ Muestreo.
time_over_using_ = ts_delta / 2;
} else {
// Incrementa el temporizador
time_over_using_ += ts_delta;
}
over_use_counter_ ++;
if (time_over_using_ > kOverUsingTimeThreshold //kOverUsingTimeThreshold es gamma_2, gamama_3=1
&& amp; 1) {
if (offset_ >= prev_offset_) {
time_over_using_ = 0;
over_use_counter_ = 0
hipótesis_ = kBwOverusing
}
}
} más {
time_over_using_ = -1
over_use_counter_ = 0;
hipótesis_ = kBwUnderusing
}
} else {
time_over_using_ = -1;
over_use_counter_ = 0; p> p>
hipótesis_ = kBwNormal;
}
Devuelve hipótesis_;