发送端两个sdp片段:SetLocalDescription,SetremoteDescription;
SetLocalDescription:
b=AS:600
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:gY3K
a=ice-pwd:1HSgJcvP5SkTGcJ8uiixrdqe
a=ice-options:trickle
a=fingerprint:sha-256 BC:7A:18:73:C5:BF:A3:9D:06:BC:13:A6:AC:99:0C:6B:BE:C8:6A:B5:DF:78:2D:C9:CE:3C:22:0E:2B:02:53:20
a=setup:actpass
a=mid:1
a=extmap:14 urn:ietf:params:rtp-hdrext:toffset
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:13 urn:3gpp:video-orientation
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:12 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:11 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
a=extmap:8 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07
a=extmap:9 http://www.webrtc.org/experiments/rtp-hdrext/color-space
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
a=sendonly
a=msid:aG6LXeJdnm3w9XiAXNENCH2AsDWvZKmUrzot 3f2908cd-12b0-4158-a9fc-9cf7c285993f
SetremoteDescription:
b=AS:600
a=rtpmap:125 H264/90000
a=rtpmap:107 rtx/90000
a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;x-google-min-bitrate=400;x-google-max-bitrate=600;profile-level-id=42e01f
a=fmtp:107 apt=125
a=rtcp-fb:125 ccm fir
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=rtcp-fb:125 goog-remb
a=extmap:14 urn:ietf:params:rtp-hdrext:toffset
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=setup:active
a=mid:1
a=recvonly
a=ice-ufrag:4689494443441386ohoc
a=ice-pwd:orts7pigqcfgxy51906986jdz5wtizq2
a=ice-options:renomination
a=rtcp-mux
a=rtcp-rsize
webrtc::VideoEncoderConfig
WebRtcVideoChannel::WebRtcVideoSendStream::CreateVideoEncoderConfig(
const VideoCodec& codec) const {
RTC_DCHECK_RUN_ON(&thread_checker_);
webrtc::VideoEncoderConfig encoder_config;
encoder_config.codec_type = webrtc::PayloadStringToCodecType(codec.name);
encoder_config.video_format =
webrtc::SdpVideoFormat(codec.name, codec.params);
bool is_screencast = parameters_.options.is_screencast.value_or(false);
if (is_screencast) {
encoder_config.min_transmit_bitrate_bps =
1000 * parameters_.options.screencast_min_bitrate_kbps.value_or(0);
encoder_config.content_type =
webrtc::VideoEncoderConfig::ContentType::kScreen;
} else {
encoder_config.min_transmit_bitrate_bps = 0;
encoder_config.content_type =
webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo;
}
// By default, the stream count for the codec configuration should match the
// number of negotiated ssrcs. But if the codec is blacklisted for simulcast
// or a screencast (and not in simulcast screenshare experiment), only
// configure a single stream.
encoder_config.number_of_streams = parameters_.config.rtp.ssrcs.size();
if (IsCodecBlacklistedForSimulcast(codec.name)) {
encoder_config.number_of_streams = 1;
}
// parameters_.max_bitrate comes from the max bitrate set at the SDP
// (m-section) level with the attribute "b=AS." Note that we override this
// value below if the RtpParameters max bitrate set with
// RtpSender::SetParameters has a lower value.
int stream_max_bitrate = parameters_.max_bitrate_bps;
// When simulcast is enabled (when there are multiple encodings),
// encodings[i].max_bitrate_bps will be enforced by
// encoder_config.simulcast_layers[i].max_bitrate_bps. Otherwise, it's
// enforced by stream_max_bitrate, taking the minimum of the two maximums
// (one coming from SDP, the other coming from RtpParameters).
if (rtp_parameters_.encodings[0].max_bitrate_bps &&
rtp_parameters_.encodings.size() == 1) {
stream_max_bitrate =
MinPositive(*(rtp_parameters_.encodings[0].max_bitrate_bps),
parameters_.max_bitrate_bps);
}
// The codec max bitrate comes from the "x-google-max-bitrate" parameter
// attribute set in the SDP for a specific codec. As done in
// WebRtcVideoChannel::SetSendParameters, this value does not override the
// stream max_bitrate set above.
int codec_max_bitrate_kbps;
if (codec.GetParam(kCodecParamMaxBitrate, &codec_max_bitrate_kbps) &&
stream_max_bitrate == -1) {
stream_max_bitrate = codec_max_bitrate_kbps * 1000;
}
encoder_config.max_bitrate_bps = stream_max_bitrate;
// The encoder config's default bitrate priority is set to 1.0,
// unless it is set through the sender's encoding parameters.
// The bitrate priority, which is used in the bitrate allocation, is done
// on a per sender basis, so we use the first encoding's value.
encoder_config.bitrate_priority =
rtp_parameters_.encodings[0].bitrate_priority;
// Application-controlled state is held in the encoder_config's
// simulcast_layers. Currently this is used to control which simulcast layers
// are active and for configuring the min/max bitrate and max framerate.
// The encoder_config's simulcast_layers is also used for non-simulcast (when
// there is a single layer).
RTC_DCHECK_GE(rtp_parameters_.encodings.size(),
encoder_config.number_of_streams);
RTC_DCHECK_GT(encoder_config.number_of_streams, 0);
// Copy all provided constraints.
encoder_config.simulcast_layers.resize(rtp_parameters_.encodings.size());
for (size_t i = 0; i < encoder_config.simulcast_layers.size(); ++i) {
encoder_config.simulcast_layers[i].active =
rtp_parameters_.encodings[i].active;
if (rtp_parameters_.encodings[i].min_bitrate_bps) {
encoder_config.simulcast_layers[i].min_bitrate_bps =
*rtp_parameters_.encodings[i].min_bitrate_bps;
}
if (rtp_parameters_.encodings[i].max_bitrate_bps) {
encoder_config.simulcast_layers[i].max_bitrate_bps =
*rtp_parameters_.encodings[i].max_bitrate_bps;
}
if (rtp_parameters_.encodings[i].max_framerate) {
encoder_config.simulcast_layers[i].max_framerate =
*rtp_parameters_.encodings[i].max_framerate;
}
if (rtp_parameters_.encodings[i].scale_resolution_down_by) {
encoder_config.simulcast_layers[i].scale_resolution_down_by =
*rtp_parameters_.encodings[i].scale_resolution_down_by;
}
if (rtp_parameters_.encodings[i].num_temporal_layers) {
encoder_config.simulcast_layers[i].num_temporal_layers =
*rtp_parameters_.encodings[i].num_temporal_layers;
}
}
int max_qp = kDefaultQpMax;
codec.GetParam(kCodecParamMaxQuantization, &max_qp);
encoder_config.video_stream_factory =
new rtc::RefCountedObject(
codec.name, max_qp, is_screencast, parameters_.conference_mode);
return encoder_config;
}
1.sdp 中有些关于带宽码率的设置,AS:行,x-google-max-bitrate,x-google-start-bitrate,x-google-min-bitrate等等,这些参数有什么作用呢?
AS:代表可用带宽,代表这路音频或者视频最多可以占用多大的带宽,比如b=AS:600就代表这路媒体流可使用多少带宽。
x-google-max-bitrate和AS作用差不多,但是有一定差异,看上面代码段,当同时设置AS行和x-google-max-bitrate时,x-google-max-bitrate会覆盖AS行,另外一点值得注意的是x-google-max-bitrate代表编码器可使用最大码率,而AS行不仅是编码器输出码率,还包括重传带宽,比如当上行网络不好时,带宽分配模块会 将AS值分给编码码率以及重传带宽。
2.如果setLocalDescription和setRemoteDescription同时设置了AS值,发送端会以哪个为准?
这时候发送端会以较小的AS值为准。
webrtc::VideoEncoderConfig
WebRtcVideoChannel::WebRtcVideoSendStream::CreateVideoEncoderConfig(
const VideoCodec& codec) const {
RTC_DCHECK_RUN_ON(&thread_checker_);
webrtc::VideoEncoderConfig encoder_config;
encoder_config.codec_type = webrtc::PayloadStringToCodecType(codec.name);
encoder_config.video_format =
webrtc::SdpVideoFormat(codec.name, codec.params);
bool is_screencast = parameters_.options.is_screencast.value_or(false);
if (is_screencast) {
encoder_config.min_transmit_bitrate_bps =
1000 * parameters_.options.screencast_min_bitrate_kbps.value_or(0);
encoder_config.content_type =
webrtc::VideoEncoderConfig::ContentType::kScreen;
} else {
encoder_config.min_transmit_bitrate_bps = 0;
encoder_config.content_type =
webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo;
}
// By default, the stream count for the codec configuration should match the
// number of negotiated ssrcs. But if the codec is disabled for simulcast
// or a screencast (and not in simulcast screenshare experiment), only
// configure a single stream.
encoder_config.number_of_streams = parameters_.config.rtp.ssrcs.size();
if (IsCodecDisabledForSimulcast(codec.name, call_->trials())) {
encoder_config.number_of_streams = 1;
}
// parameters_.max_bitrate comes from the max bitrate set at the SDP
// (m-section) level with the attribute "b=AS." Note that we override this
// value below if the RtpParameters max bitrate set with
// RtpSender::SetParameters has a lower value.
int stream_max_bitrate = parameters_.max_bitrate_bps;
// When simulcast is enabled (when there are multiple encodings),
// encodings[i].max_bitrate_bps will be enforced by
// encoder_config.simulcast_layers[i].max_bitrate_bps. Otherwise, it's
// enforced by stream_max_bitrate, taking the minimum of the two maximums
// (one coming from SDP, the other coming from RtpParameters).
if (rtp_parameters_.encodings[0].max_bitrate_bps &&
rtp_parameters_.encodings.size() == 1) {
stream_max_bitrate =
MinPositive(*(rtp_parameters_.encodings[0].max_bitrate_bps),
parameters_.max_bitrate_bps);
}
// The codec max bitrate comes from the "x-google-max-bitrate" parameter
// attribute set in the SDP for a specific codec. As done in
// WebRtcVideoChannel::SetSendParameters, this value does not override the
// stream max_bitrate set above.
int codec_max_bitrate_kbps;
if (codec.GetParam(kCodecParamMaxBitrate, &codec_max_bitrate_kbps) &&
stream_max_bitrate == -1) {
stream_max_bitrate = codec_max_bitrate_kbps * 1000;
}
encoder_config.max_bitrate_bps = stream_max_bitrate;
// The encoder config's default bitrate priority is set to 1.0,
// unless it is set through the sender's encoding parameters.
// The bitrate priority, which is used in the bitrate allocation, is done
// on a per sender basis, so we use the first encoding's value.
encoder_config.bitrate_priority =
rtp_parameters_.encodings[0].bitrate_priority;
// Application-controlled state is held in the encoder_config's
// simulcast_layers. Currently this is used to control which simulcast layers
// are active and for configuring the min/max bitrate and max framerate.
// The encoder_config's simulcast_layers is also used for non-simulcast (when
// there is a single layer).
RTC_DCHECK_GE(rtp_parameters_.encodings.size(),
encoder_config.number_of_streams);
RTC_DCHECK_GT(encoder_config.number_of_streams, 0);
// Copy all provided constraints.
encoder_config.simulcast_layers.resize(rtp_parameters_.encodings.size());
for (size_t i = 0; i < encoder_config.simulcast_layers.size(); ++i) {
encoder_config.simulcast_layers[i].active =
rtp_parameters_.encodings[i].active;
encoder_config.simulcast_layers[i].scalability_mode =
rtp_parameters_.encodings[i].scalability_mode;
if (rtp_parameters_.encodings[i].min_bitrate_bps) {
encoder_config.simulcast_layers[i].min_bitrate_bps =
*rtp_parameters_.encodings[i].min_bitrate_bps;
}
if (rtp_parameters_.encodings[i].max_bitrate_bps) {
encoder_config.simulcast_layers[i].max_bitrate_bps =
*rtp_parameters_.encodings[i].max_bitrate_bps;
}
if (rtp_parameters_.encodings[i].max_framerate) {
encoder_config.simulcast_layers[i].max_framerate =
*rtp_parameters_.encodings[i].max_framerate;
}
if (rtp_parameters_.encodings[i].scale_resolution_down_by) {
encoder_config.simulcast_layers[i].scale_resolution_down_by =
*rtp_parameters_.encodings[i].scale_resolution_down_by;
}
if (rtp_parameters_.encodings[i].num_temporal_layers) {
encoder_config.simulcast_layers[i].num_temporal_layers =
*rtp_parameters_.encodings[i].num_temporal_layers;
}
}
encoder_config.legacy_conference_mode = parameters_.conference_mode;
encoder_config.is_quality_scaling_allowed =
!disable_automatic_resize_ && !is_screencast &&
(parameters_.config.rtp.ssrcs.size() == 1 ||
NumActiveStreams(rtp_parameters_) == 1);
int max_qp = kDefaultQpMax;
codec.GetParam(kCodecParamMaxQuantization, &max_qp);
// wx add begin
// encoder_config.min_transmit_bitrate_bps = 800*1000;
// encoder_config.max_bitrate_bps = 1200*1000;
RTC_LOG(LS_ERROR) << "wx_test:"
<< "codec:" << codec.ToString().c_str() << "encoder_config"
<< encoder_config.ToString();
// wx add start
encoder_config.video_stream_factory =
rtc::make_ref_counted(
codec.name, max_qp, is_screencast, parameters_.conference_mode);
return encoder_config;
}
3.x-google-min-bitrate这个只有什么作用?
这个参数是控制最小可用带宽的,比如现在x-google-max-bitrate=600,x-google-min-bitrate=400;(使用GCC时)当上行网络不好出现丢包时,接收端会反馈给发送端丢包率,接收端会根据丢包率来调整发送端带宽,如果不对最小带宽限制,GCC出的码率会降的很低,这时候如果需要发送关键帧将会卡主很久,因此这里设置最小码率对GCC做些限制,这也是为什么使用Remb而不是Transport-cc的探测带宽主要原因,可能T-cc会探测的更准确些,但是服务器控制不了,还是使用了Remb。
struct BitrateConstraints {
int min_bitrate_bps = 0;
int start_bitrate_bps = kDefaultStartBitrateBps;
int max_bitrate_bps = -1;
private:
static constexpr int kDefaultStartBitrateBps = 300000;
};
webrtc::BitrateConstraints GetBitrateConfigForCodec(const Codec& codec) {
webrtc::BitrateConstraints config;
int bitrate_kbps = 0;
if (codec.GetParam(kCodecParamMinBitrate, &bitrate_kbps) &&
bitrate_kbps > 0) {
config.min_bitrate_bps = bitrate_kbps * 1000;
} else {
config.min_bitrate_bps = 0;
}
if (codec.GetParam(kCodecParamStartBitrate, &bitrate_kbps) &&
bitrate_kbps > 0) {
config.start_bitrate_bps = bitrate_kbps * 1000;
} else {
// Do not reconfigure start bitrate unless it's specified and positive.
config.start_bitrate_bps = -1;
}
if (codec.GetParam(kCodecParamMaxBitrate, &bitrate_kbps) &&
bitrate_kbps > 0) {
config.max_bitrate_bps = bitrate_kbps * 1000;
} else {
config.max_bitrate_bps = -1;
}
return config;
}
改图是发送端的videoBwe图,最开始设置总带宽为600,实际编码码率在600以下波动,当发送端设置丢包时,GCC估计出的带宽迅速下降到400,因为我设置了x-google-min-bitrate=400,不然根据GCC的带宽估计算法持续反馈丢包率的时候会降到十几K。这时总带宽会降到400之后不在下降,然后码率分配模块会将总带宽分配给编码码率和重传带宽,这块带宽怎么分配的后面再讲。