@@ -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+
13581410srs_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+
23732485srs_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" ;
0 commit comments