Skip to content

Support transmux RTC to RTMP. 4.0.95 #2303

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ Other important wiki:

## V4 changes

* v5.0, 2021-04-20, Support RTC2RTMP bridger and shared FastTimer. 4.0.95
* v5.0, 2021-04-20, Refine transcoder to support aac2opus and opus2aac. 4.0.94
* v4.0, 2021-05-01, Timer: Extract and apply shared FastTimer. 4.0.93
* v4.0, 2021-04-29, RTC: Support AV1 for Chrome M90. 4.0.91
* v4.0, 2021-04-24, Change push-RTSP as deprecated feature.
* v4.0, 2021-04-24, Player: Change the default from RTMP to HTTP-FLV.
Expand Down
9 changes: 9 additions & 0 deletions trunk/conf/full.conf
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,15 @@ vhost rtc.vhost.srs.com {
# discard Discard aac audio packet.
# default: transcode
aac transcode;
###############################################################
# For transmuxing RTC to RTMP.
# Whether trans-mux RTC to RTMP streaming.
# Default: off
rtc_to_rtmp off;
# The PLI interval in seconds, for RTC to RTMP.
# Note the available range is [0.5, 30]
# Default: 6.0
pli_for_rtmp 6.0;
}
###############################################################
# For transmuxing RTMP to RTC, it will impact the default values if RTC is on.
Expand Down
43 changes: 42 additions & 1 deletion trunk/src/app/srs_app_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3940,7 +3940,8 @@ srs_error_t SrsConfig::check_normal_config()
for (int j = 0; j < (int)conf->directives.size(); j++) {
string m = conf->at(j)->name;
if (m != "enabled" && m != "bframe" && m != "aac" && m != "stun_timeout" && m != "stun_strict_check"
&& m != "dtls_role" && m != "dtls_version" && m != "drop_for_pt") {
&& m != "dtls_role" && m != "dtls_version" && m != "drop_for_pt" && m != "rtc_to_rtmp"
&& m != "pli_for_rtmp") {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.rtc.%s of %s", m.c_str(), vhost->arg0().c_str());
}
}
Expand Down Expand Up @@ -5226,6 +5227,46 @@ int SrsConfig::get_rtc_drop_for_pt(string vhost)
return ::atoi(conf->arg0().c_str());
}

bool SrsConfig::get_rtc_to_rtmp(string vhost)
{
static bool DEFAULT = false;

SrsConfDirective* conf = get_rtc(vhost);
if (!conf) {
return DEFAULT;
}

conf = conf->get("rtc_to_rtmp");
if (!conf || conf->arg0().empty()) {
return DEFAULT;
}

return SRS_CONF_PERFER_FALSE(conf->arg0());
}

srs_utime_t SrsConfig::get_rtc_pli_for_rtmp(string vhost)
{
static srs_utime_t DEFAULT = 6 * SRS_UTIME_SECONDS;

SrsConfDirective* conf = get_rtc(vhost);
if (!conf) {
return DEFAULT;
}

conf = conf->get("pli_for_rtmp");
if (!conf || conf->arg0().empty()) {
return DEFAULT;
}

srs_utime_t v = (srs_utime_t)(::atof(conf->arg0().c_str()) * SRS_UTIME_SECONDS);
if (v < 500 * SRS_UTIME_MILLISECONDS || v > 30 * SRS_UTIME_SECONDS) {
srs_warn("Reset pli %dms to %dms", srsu2msi(v), srsu2msi(DEFAULT));
return DEFAULT;
}

return v;
}

bool SrsConfig::get_rtc_nack_enabled(string vhost)
{
static bool DEFAULT = true;
Expand Down
2 changes: 2 additions & 0 deletions trunk/src/app/srs_app_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,8 @@ class SrsConfig
std::string get_rtc_dtls_role(std::string vhost);
std::string get_rtc_dtls_version(std::string vhost);
int get_rtc_drop_for_pt(std::string vhost);
bool get_rtc_to_rtmp(std::string vhost);
srs_utime_t get_rtc_pli_for_rtmp(std::string vhost);
bool get_rtc_nack_enabled(std::string vhost);
bool get_rtc_nack_no_copy(std::string vhost);
bool get_rtc_twcc_enabled(std::string vhost);
Expand Down
144 changes: 144 additions & 0 deletions trunk/src/app/srs_app_hourglass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,22 @@ using namespace std;

#include <srs_kernel_error.hpp>
#include <srs_kernel_log.hpp>
#include <srs_kernel_utility.hpp>

#include <srs_protocol_kbps.hpp>

SrsPps* _srs_pps_timer = new SrsPps();

extern SrsPps* _srs_pps_clock_15ms;
extern SrsPps* _srs_pps_clock_20ms;
extern SrsPps* _srs_pps_clock_25ms;
extern SrsPps* _srs_pps_clock_30ms;
extern SrsPps* _srs_pps_clock_35ms;
extern SrsPps* _srs_pps_clock_40ms;
extern SrsPps* _srs_pps_clock_80ms;
extern SrsPps* _srs_pps_clock_160ms;
extern SrsPps* _srs_pps_timer_s;

ISrsHourGlass::ISrsHourGlass()
{
}
Expand Down Expand Up @@ -89,6 +100,14 @@ srs_error_t SrsHourGlass::tick(int event, srs_utime_t interval)
return err;
}

void SrsHourGlass::untick(int event)
{
map<int, srs_utime_t>::iterator it = ticks.find(event);
if (it != ticks.end()) {
ticks.erase(it);
}
}

srs_error_t SrsHourGlass::cycle()
{
srs_error_t err = srs_success;
Expand Down Expand Up @@ -119,3 +138,128 @@ srs_error_t SrsHourGlass::cycle()

return err;
}

ISrsFastTimer::ISrsFastTimer()
{
}

ISrsFastTimer::~ISrsFastTimer()
{
}

SrsFastTimer::SrsFastTimer(std::string label, srs_utime_t resolution)
{
timer_ = new SrsHourGlass(label, this, resolution);
}

SrsFastTimer::~SrsFastTimer()
{
srs_freep(timer_);
}

srs_error_t SrsFastTimer::start()
{
srs_error_t err = srs_success;

if ((err = timer_->start()) != srs_success) {
return srs_error_wrap(err, "start timer");
}

return err;
}

void SrsFastTimer::subscribe(srs_utime_t interval, ISrsFastTimer* timer)
{
static int g_event = 0;

int event = g_event++;

// TODO: FIXME: Error leak. Change tick to void in future.
timer_->tick(event, interval);

handlers_[event] = timer;
}

void SrsFastTimer::unsubscribe(ISrsFastTimer* timer)
{
for (map<int, ISrsFastTimer*>::iterator it = handlers_.begin(); it != handlers_.end();) {
if (it->second != timer) {
++it;
continue;
}

handlers_.erase(it++);

int event = it->first;
timer_->untick(event);
}
}

srs_error_t SrsFastTimer::notify(int event, srs_utime_t interval, srs_utime_t tick)
{
srs_error_t err = srs_success;

for (map<int, ISrsFastTimer*>::iterator it = handlers_.begin(); it != handlers_.end(); ++it) {
ISrsFastTimer* timer = it->second;

if (event != it->first) {
continue;
}

if ((err = timer->on_timer(interval, tick)) != srs_success) {
return srs_error_wrap(err, "tick for event=%d, interval=%dms, tick=%dms",
event, srsu2msi(interval), srsu2msi(tick));
}

break;
}

return err;
}

SrsClockWallMonitor::SrsClockWallMonitor()
{
}

SrsClockWallMonitor::~SrsClockWallMonitor()
{
}

srs_error_t SrsClockWallMonitor::on_timer(srs_utime_t interval, srs_utime_t tick)
{
srs_error_t err = srs_success;

static srs_utime_t clock = 0;

srs_utime_t now = srs_update_system_time();
if (!clock) {
clock = now;
return err;
}

srs_utime_t elapsed = now - clock;
clock = now;

if (elapsed <= 15 * SRS_UTIME_MILLISECONDS) {
++_srs_pps_clock_15ms->sugar;
} else if (elapsed <= 21 * SRS_UTIME_MILLISECONDS) {
++_srs_pps_clock_20ms->sugar;
} else if (elapsed <= 25 * SRS_UTIME_MILLISECONDS) {
++_srs_pps_clock_25ms->sugar;
} else if (elapsed <= 30 * SRS_UTIME_MILLISECONDS) {
++_srs_pps_clock_30ms->sugar;
} else if (elapsed <= 35 * SRS_UTIME_MILLISECONDS) {
++_srs_pps_clock_35ms->sugar;
} else if (elapsed <= 40 * SRS_UTIME_MILLISECONDS) {
++_srs_pps_clock_40ms->sugar;
} else if (elapsed <= 80 * SRS_UTIME_MILLISECONDS) {
++_srs_pps_clock_80ms->sugar;
} else if (elapsed <= 160 * SRS_UTIME_MILLISECONDS) {
++_srs_pps_clock_160ms->sugar;
} else {
++_srs_pps_timer_s->sugar;
}

return err;
}

47 changes: 46 additions & 1 deletion trunk/src/app/srs_app_hourglass.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class ISrsHourGlass
//
// // The hg will create a thread for timer.
// hg->start();
class SrsHourGlass : virtual public ISrsCoroutineHandler
class SrsHourGlass : public ISrsCoroutineHandler
{
private:
std::string label_;
Expand Down Expand Up @@ -96,10 +96,55 @@ class SrsHourGlass : virtual public ISrsCoroutineHandler
// @param interval the interval in srs_utime_t of tick.
virtual srs_error_t tick(srs_utime_t interval);
virtual srs_error_t tick(int event, srs_utime_t interval);
// Remove the tick by event.
void untick(int event);
public:
// Cycle the hourglass, which will sleep resolution every time.
// and call handler when ticked.
virtual srs_error_t cycle();
};

// The handler for fast timer.
class ISrsFastTimer
{
public:
ISrsFastTimer();
virtual ~ISrsFastTimer();
public:
// Tick when timer is active.
virtual srs_error_t on_timer(srs_utime_t interval, srs_utime_t tick) = 0;
};

// The fast timer, shared by objects, for high performance.
// For example, we should never start a timer for each connection or publisher or player,
// instead, we should start only one fast timer in server.
class SrsFastTimer : public ISrsHourGlass
{
private:
SrsHourGlass* timer_;
std::map<int, ISrsFastTimer*> handlers_;
public:
SrsFastTimer(std::string label, srs_utime_t resolution);
virtual ~SrsFastTimer();
public:
srs_error_t start();
public:
void subscribe(srs_utime_t interval, ISrsFastTimer* timer);
void unsubscribe(ISrsFastTimer* timer);
// Interface ISrsHourGlass
private:
virtual srs_error_t notify(int event, srs_utime_t interval, srs_utime_t tick);
};

// To monitor the system wall clock timer deviation.
class SrsClockWallMonitor : public ISrsFastTimer
{
public:
SrsClockWallMonitor();
virtual ~SrsClockWallMonitor();
// interface ISrsFastTimer
private:
srs_error_t on_timer(srs_utime_t interval, srs_utime_t tick);
};

#endif
Loading