Skip to content

Commit c182f09

Browse files
committed
add the feature of bitrate limitation for rtc publishing through google remb mechanism
specify the bitrate through the following way: 1. according to the configure file 2. http query parameter 3. http json property (cherry picked from commit c4b4aa6)
1 parent 55bd0bb commit c182f09

8 files changed

Lines changed: 204 additions & 3 deletions

trunk/conf/full.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,9 @@ vhost rtc.vhost.srs.com {
595595
# [8000, 320000]
596596
# default: 48000
597597
aac_bitrate 48000;
598+
# The bitrate limitation for publish in bps, 0 - no limiting
599+
# default: 0
600+
bitrate 0;
598601
}
599602
###############################################################
600603
# For transmuxing RTMP to RTC, it will impact the default values if RTC is on.

trunk/src/app/srs_app_config.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2745,7 +2745,7 @@ srs_error_t SrsConfig::check_normal_config()
27452745
&& m != "bframe" && m != "aac" && m != "stun_timeout" && m != "stun_strict_check"
27462746
&& m != "dtls_role" && m != "dtls_version" && m != "drop_for_pt" && m != "rtc_to_rtmp"
27472747
&& m != "pli_for_rtmp" && m != "rtmp_to_rtc" && m != "keep_bframe" && m != "opus_bitrate"
2748-
&& m != "aac_bitrate" && m != "keep_avc_nalu_sei") {
2748+
&& m != "aac_bitrate" && m != "keep_avc_nalu_sei" && m != "bitrate") {
27492749
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.rtc.%s of %s", m.c_str(), vhost->arg0().c_str());
27502750
}
27512751
}
@@ -4651,6 +4651,34 @@ bool SrsConfig::get_rtc_to_rtmp(string vhost)
46514651
return SRS_CONF_PREFER_FALSE(conf->arg0());
46524652
}
46534653

4654+
uint64_t SrsConfig::get_rtc_bitrate(string vhost)
4655+
{
4656+
static uint64_t DEFAULT = 0;
4657+
4658+
SrsConfDirective* conf = get_rtc(vhost);
4659+
if (!conf) {
4660+
return DEFAULT;
4661+
}
4662+
4663+
conf = conf->get("bitrate");
4664+
if (!conf || conf->arg0().empty()) {
4665+
return DEFAULT;
4666+
}
4667+
4668+
uint64_t v = (uint64_t)(::atoll(conf->arg0().c_str()));
4669+
if ( v > 100 * 1024 * 1024) {
4670+
srs_warn("Invalid bitrate(%ll), No bitrate control", (long long) v);
4671+
return DEFAULT;
4672+
}
4673+
4674+
if (v < 64000){
4675+
4676+
srs_warn("Invalid bitrate(%ll), reset it to 64000 bps", (long long) v);
4677+
v = 64000;
4678+
}
4679+
4680+
return v;
4681+
}
46544682
srs_utime_t SrsConfig::get_rtc_pli_for_rtmp(string vhost)
46554683
{
46564684
static srs_utime_t DEFAULT = 6 * SRS_UTIME_SECONDS;

trunk/src/app/srs_app_config.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ class SrsConfig
544544
std::string get_rtc_dtls_version(std::string vhost);
545545
int get_rtc_drop_for_pt(std::string vhost);
546546
bool get_rtc_to_rtmp(std::string vhost);
547+
uint64_t get_rtc_bitrate(std::string vhost);
547548
srs_utime_t get_rtc_pli_for_rtmp(std::string vhost);
548549
bool get_rtc_nack_enabled(std::string vhost);
549550
bool get_rtc_nack_no_copy(std::string vhost);

trunk/src/app/srs_app_rtc_api.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,12 @@ srs_error_t SrsGoApiRtcPublish::do_serve_http(ISrsHttpResponseWriter* w, ISrsHtt
432432
tid = prop->to_str();
433433
}
434434

435+
uint64_t bitrate = 0;
436+
if ((prop = req->ensure_property_integer("bitrate")) != NULL) {
437+
bitrate = prop->to_integer();
438+
}
439+
440+
435441
// The RTC user config object.
436442
SrsRtcUserConfig ruc;
437443
ruc.req_->ip = clientip;
@@ -457,16 +463,31 @@ srs_error_t SrsGoApiRtcPublish::do_serve_http(ISrsHttpResponseWriter* w, ISrsHtt
457463
}
458464
string codec = r->query_get("codec");
459465

460-
srs_trace("RTC publish %s, api=%s, tid=%s, clientip=%s, app=%s, stream=%s, offer=%dB, eip=%s, codec=%s",
466+
string bitrate_query = r->query_get("bitrate");
467+
if(bitrate == 0 && ! bitrate_query.empty()){
468+
bitrate = ::atoll(bitrate_query.c_str());
469+
}
470+
if (bitrate > 100 * 1024 * 1024) {
471+
srs_warn("Request Invalid bitrate(%ll), No bitrate control", (long long)bitrate);
472+
bitrate = 0;
473+
}
474+
if (bitrate < 64000 && bitrate > 0){
475+
srs_warn("Request Invalid bitrate(%ll), reset it to 64000 bps", (long long)bitrate);
476+
bitrate = 64000;
477+
}
478+
479+
srs_trace("RTC publish %s, api=%s, tid=%s, clientip=%s, app=%s, stream=%s, offer=%dB, eip=%s, codec=%s, bitrate=%llu",
461480
streamurl.c_str(), api.c_str(), tid.c_str(), clientip.c_str(), ruc.req_->app.c_str(), ruc.req_->stream.c_str(),
462-
remote_sdp_str.length(), eip.c_str(), codec.c_str()
481+
remote_sdp_str.length(), eip.c_str(), codec.c_str(), bitrate
463482
);
464483

465484
ruc.eip_ = eip;
466485
ruc.codec_ = codec;
467486
ruc.publish_ = true;
468487
ruc.dtls_ = ruc.srtp_ = true;
469488

489+
ruc.req_->bitrate = bitrate;
490+
470491
// TODO: FIXME: It seems remote_sdp doesn't represents the full SDP information.
471492
ruc.remote_sdp_str_ = remote_sdp_str;
472493
if ((err = ruc.remote_sdp_.parse(remote_sdp_str)) != srs_success) {

trunk/src/app/srs_app_rtc_conn.cpp

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,12 @@ srs_error_t SrsRtcPublishRtcpTimer::on_timer(srs_utime_t interval)
986986
srs_warn("XR err %s", srs_error_desc(err).c_str());
987987
srs_freep(err);
988988
}
989+
990+
// For REMB
991+
if((err = p_->send_rtcp_remb()) != srs_success){
992+
srs_warn("remb err %s", srs_error_desc(err).c_str());
993+
srs_freep(err);
994+
}
989995

990996
return err;
991997
}
@@ -1117,6 +1123,9 @@ SrsRtcPublishStream::SrsRtcPublishStream(SrsRtcConnection* session, const SrsCon
11171123

11181124
pli_worker_ = new SrsRtcPLIWorker(this);
11191125
last_time_send_twcc_ = 0;
1126+
1127+
bitrate_ = 0;
1128+
remb_startup_ = 4;
11201129

11211130
timer_rtcp_ = new SrsRtcPublishRtcpTimer(this);
11221131
timer_twcc_ = new SrsRtcPublishTwccTimer(this);
@@ -1199,6 +1208,12 @@ srs_error_t SrsRtcPublishStream::initialize(SrsRequest* r, SrsRtcSourceDescripti
11991208
pt_to_drop_ = (uint16_t)_srs_config->get_rtc_drop_for_pt(req_->vhost);
12001209
twcc_enabled_ = _srs_config->get_rtc_twcc_enabled(req_->vhost);
12011210

1211+
bitrate_ = _srs_config->get_rtc_bitrate(req_->vhost);
1212+
if(r->bitrate != 0){
1213+
bitrate_ = r->bitrate;
1214+
}
1215+
remb_startup_ = 4;
1216+
12021217
// No TWCC when negotiate, disable it.
12031218
if (twcc_id <= 0) {
12041219
twcc_enabled_ = false;
@@ -1355,6 +1370,43 @@ srs_error_t SrsRtcPublishStream::send_rtcp_rr()
13551370
return err;
13561371
}
13571372

1373+
1374+
srs_error_t SrsRtcPublishStream::send_rtcp_remb()
1375+
{
1376+
srs_error_t err = srs_success;
1377+
uint32_t bitrate = bitrate_;
1378+
1379+
// no bitrate control
1380+
if(bitrate_ == 0){
1381+
return err;
1382+
}
1383+
1384+
// no rtc session
1385+
if(session_ == NULL){
1386+
return err;
1387+
}
1388+
1389+
// no video tracks
1390+
if(video_tracks_.size() == 0){
1391+
return err;
1392+
}
1393+
1394+
if(remb_startup_ > 0){
1395+
bitrate = bitrate / remb_startup_;
1396+
remb_startup_ --;
1397+
}
1398+
1399+
//only send for video 0 track
1400+
SrsRtcVideoRecvTrack* track = video_tracks_.at(0);
1401+
uint32_t ssrc = track->get_ssrc();
1402+
if ((err = session_->send_rtcp_remb(ssrc, bitrate) ) != srs_success) {
1403+
return srs_error_wrap(err, "rtcp remb send error(ssrc=%u, bitrate=%llu)" , ssrc, (unsigned long long)bitrate);
1404+
}
1405+
1406+
1407+
return err;
1408+
}
1409+
13581410
srs_error_t SrsRtcPublishStream::send_rtcp_xr_rrtr()
13591411
{
13601412
srs_error_t err = srs_success;
@@ -1481,6 +1533,16 @@ srs_error_t SrsRtcPublishStream::do_on_rtp_plaintext(SrsRtpPacket*& pkt, SrsBuff
14811533
return srs_error_new(ERROR_RTC_RTP, "unknown ssrc=%u", ssrc);
14821534
}
14831535

1536+
// For remb startup, according to janus
1537+
if(video_track != NULL && bitrate_ != 0 && remb_startup_ > 0){
1538+
1539+
if ((err = send_rtcp_remb()) != srs_success) {
1540+
srs_warn("send rtcp remb failed, %s", srs_error_desc(err).c_str());
1541+
srs_freep(err);
1542+
}
1543+
1544+
}
1545+
14841546
// If circuit-breaker is enabled, disable nack.
14851547
if (_srs_circuit_breaker->hybrid_critical_water_level()) {
14861548
++_srs_pps_snack4->sugar;
@@ -2370,6 +2432,56 @@ void SrsRtcConnection::check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ss
23702432
send_rtcp(stream.data(), stream.pos());
23712433
}
23722434

2435+
srs_error_t SrsRtcConnection::send_rtcp_remb(uint32_t ssrc, const uint64_t& bitrate)
2436+
{
2437+
srs_error_t err = srs_success;
2438+
int min_len = 20 + 4;
2439+
2440+
// @see https://datatracker.ietf.org/doc/html/draft-alvestrand-rmcat-remb-03#section-2.2
2441+
char buf[kRtpPacketSize];
2442+
SrsBuffer stream(buf, sizeof(buf));
2443+
//header
2444+
stream.write_1bytes(0x8F);
2445+
stream.write_1bytes(kPsFb);
2446+
stream.write_2bytes((min_len/4) - 1);
2447+
//SSRC of packet sender
2448+
stream.write_4bytes(ssrc); // TODO: FIXME: Should be 1?
2449+
//SSRC of media source, always 0
2450+
stream.write_4bytes(0);
2451+
2452+
//Unique identifier (32 bits): Always 'R' 'E' 'M' 'B' (4 ASCII characters).
2453+
stream.write_1bytes('R');
2454+
stream.write_1bytes('E');
2455+
stream.write_1bytes('M');
2456+
stream.write_1bytes('B');
2457+
2458+
//Num SSRC (8 bits)
2459+
stream.write_1bytes(1);
2460+
2461+
/* bitrate --> brexp/brmantissa */
2462+
uint8_t b = 0;
2463+
uint8_t newbrexp = 0;
2464+
uint32_t newbrmantissa = 0;
2465+
for(b=0; b<32; b++) {
2466+
if(bitrate <= ((uint32_t) 0x3FFFF << b)) {
2467+
newbrexp = b;
2468+
break;
2469+
}
2470+
}
2471+
if(b > 31)
2472+
b = 31;
2473+
newbrmantissa = bitrate >> b;
2474+
// BR Exp (6 bits) + BR Mantissa (18 bits)
2475+
stream.write_1bytes((uint8_t)((newbrexp << 2) + ((newbrmantissa >> 16) & 0x03)));
2476+
stream.write_1bytes((uint8_t)(newbrmantissa >> 8));
2477+
stream.write_1bytes((uint8_t)(newbrmantissa));
2478+
2479+
//SSRC feedback
2480+
stream.write_4bytes(ssrc);
2481+
2482+
return send_rtcp(stream.data(), stream.pos());
2483+
}
2484+
23732485
srs_error_t SrsRtcConnection::send_rtcp_rr(uint32_t ssrc, SrsRtpRingBuffer* rtp_queue, const uint64_t& last_send_systime, const SrsNtp& last_send_ntp)
23742486
{
23752487
++_srs_pps_srtcps->sugar;
@@ -2651,6 +2763,10 @@ srs_error_t SrsRtcConnection::negotiate_publish_capability(SrsRtcUserConfig* ruc
26512763

26522764
bool nack_enabled = _srs_config->get_rtc_nack_enabled(req->vhost);
26532765
bool twcc_enabled = _srs_config->get_rtc_twcc_enabled(req->vhost);
2766+
2767+
bool remb_enabled = _srs_config->get_rtc_bitrate(req->vhost) > 0 ||
2768+
req->bitrate > 0;
2769+
26542770
// TODO: FIME: Should check packetization-mode=1 also.
26552771
bool has_42e01f = srs_sdp_has_h264_profile(remote_sdp, "42e01f");
26562772

@@ -2751,6 +2867,11 @@ srs_error_t SrsRtcConnection::negotiate_publish_capability(SrsRtcUserConfig* ruc
27512867
video_payload->rtcp_fbs_.push_back(rtcp_fb);
27522868
}
27532869
}
2870+
if(remb_enabled) {
2871+
if (rtcp_fb == "goog-remb") {
2872+
video_payload->rtcp_fbs_.push_back(rtcp_fb);
2873+
}
2874+
}
27542875
}
27552876

27562877
track_desc->type_ = "video";
@@ -2785,6 +2906,11 @@ srs_error_t SrsRtcConnection::negotiate_publish_capability(SrsRtcUserConfig* ruc
27852906
video_payload->rtcp_fbs_.push_back(rtcp_fb);
27862907
}
27872908
}
2909+
if(remb_enabled) {
2910+
if (rtcp_fb == "goog-remb") {
2911+
video_payload->rtcp_fbs_.push_back(rtcp_fb);
2912+
}
2913+
}
27882914
}
27892915

27902916
track_desc->type_ = "video";
@@ -2836,6 +2962,11 @@ srs_error_t SrsRtcConnection::negotiate_publish_capability(SrsRtcUserConfig* ruc
28362962
video_payload->rtcp_fbs_.push_back(rtcp_fb);
28372963
}
28382964
}
2965+
if(remb_enabled) {
2966+
if (rtcp_fb == "goog-remb") {
2967+
video_payload->rtcp_fbs_.push_back(rtcp_fb);
2968+
}
2969+
}
28392970
}
28402971

28412972
track_desc->type_ = "video";
@@ -2873,6 +3004,11 @@ srs_error_t SrsRtcConnection::negotiate_publish_capability(SrsRtcUserConfig* ruc
28733004
video_payload->rtcp_fbs_.push_back(rtcp_fb);
28743005
}
28753006
}
3007+
if(remb_enabled) {
3008+
if (rtcp_fb == "goog-remb") {
3009+
video_payload->rtcp_fbs_.push_back(rtcp_fb);
3010+
}
3011+
}
28763012
}
28773013

28783014
track_desc->type_ = "video";

trunk/src/app/srs_app_rtc_conn.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,8 @@ class SrsRtcPublishStream : public ISrsRtspPacketDecodeHandler
341341
bool nack_enabled_;
342342
bool nack_no_copy_;
343343
bool twcc_enabled_;
344+
uint64_t bitrate_;
345+
uint64_t remb_startup_;
344346
private:
345347
bool request_keyframe_;
346348
SrsErrorPithyPrint* pli_epp;
@@ -372,6 +374,7 @@ class SrsRtcPublishStream : public ISrsRtspPacketDecodeHandler
372374
private:
373375
srs_error_t send_rtcp_rr();
374376
srs_error_t send_rtcp_xr_rrtr();
377+
srs_error_t send_rtcp_remb();
375378
public:
376379
srs_error_t on_rtp_cipher(char* buf, int nb_buf);
377380
srs_error_t on_rtp_plaintext(char* buf, int nb_buf);
@@ -535,6 +538,7 @@ class SrsRtcConnection : public ISrsResource, public ISrsDisposingHandler, publi
535538
srs_error_t send_rtcp(char *data, int nb_data);
536539
void check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ssrc, uint32_t& sent_nacks, uint32_t& timeout_nacks);
537540
srs_error_t send_rtcp_rr(uint32_t ssrc, SrsRtpRingBuffer* rtp_queue, const uint64_t& last_send_systime, const SrsNtp& last_send_ntp);
541+
srs_error_t send_rtcp_remb(uint32_t ssrc, const uint64_t& bitrate);
538542
srs_error_t send_rtcp_xr_rrtr(uint32_t ssrc);
539543
srs_error_t send_rtcp_fb_pli(uint32_t ssrc, const SrsContextId& cid_of_subscriber);
540544
public:

trunk/src/protocol/srs_protocol_rtmp_stack.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,6 +1463,8 @@ SrsRequest::SrsRequest()
14631463
args = NULL;
14641464

14651465
protocol = "rtmp";
1466+
1467+
bitrate = 0;
14661468
}
14671469

14681470
SrsRequest::~SrsRequest()
@@ -1492,6 +1494,7 @@ SrsRequest* SrsRequest::copy()
14921494
}
14931495

14941496
cp->protocol = protocol;
1497+
cp->bitrate = bitrate;
14951498

14961499
return cp;
14971500
}
@@ -1521,6 +1524,8 @@ void SrsRequest::update_auth(SrsRequest* req)
15211524
}
15221525

15231526
protocol = req->protocol;
1527+
1528+
bitrate = req->bitrate;
15241529

15251530
srs_info("update req of soruce for auth ok");
15261531
}

trunk/src/protocol/srs_protocol_rtmp_stack.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,9 @@ class SrsRequest
441441
// used for edge traverse to origin authentication,
442442
// @see https://github.com/ossrs/srs/issues/104
443443
SrsAmf0Object* args;
444+
445+
//the max bitrate for client
446+
uint64_t bitrate;
444447
public:
445448
SrsRequest();
446449
virtual ~SrsRequest();

0 commit comments

Comments
 (0)