winlin

fix #108: disable the time jitter for encoder non-monotonical stream. 0.9.133

... ... @@ -241,6 +241,7 @@ Supported operating systems and hardware:
* 2013-10-17, Created.<br/>
## History
* v1.0, 2014-06-25, fix [#108](https://github.com/winlinvip/simple-rtmp-server/issues/108), disable the time jitter for encoder non-monotonical stream. 0.9.133
* v1.0, 2014-06-23, support report summaries in heartbeat. 0.9.132
* v1.0, 2014-06-22, performance refine, support [3k+](https://github.com/winlinvip/simple-rtmp-server/wiki/Performance#%E6%80%A7%E8%83%BD%E4%BE%8B%E8%A1%8C%E6%8A%A5%E5%91%8A4k) connections(270kbps). 0.9.130
* v1.0, 2014-06-21, support edge [token traverse](https://github.com/winlinvip/simple-rtmp-server/wiki/DRM#tokentraverse), fix [#104](https://github.com/winlinvip/simple-rtmp-server/issues/104). 0.9.129
... ...
... ... @@ -187,6 +187,18 @@ vhost dvr.srs.com {
# the param for plan(segment), in seconds.
# default: 30
dvr_duration 30;
# about the stream monotonically increasing:
# 1. video timestamp is monotonically increasing,
# 2. audio timestamp is monotonically increasing,
# 3. video and audio timestamp is interleaved monotonically increasing.
# it's specified by RTMP specification, @see 3. Byte Order, Alignment, and Time Format
# however, some encoder cannot provides this feature, please set this to off to ignore time jitter.
# the time jitter algorithm:
# 1. full, to ensure stream start at zero, and ensure stream monotonically increasing.
# 2. zero, only ensure sttream start at zero, ignore timestamp jitter.
# 3. off, disable the time jitter algorithm, like atc.
# default: full
time_jitter full;
}
}
... ... @@ -906,6 +918,22 @@ vhost chunksize.srs.com {
chunk_size 128;
}
# vhost for time jitter
vhost jitter.srs.com {
# about the stream monotonically increasing:
# 1. video timestamp is monotonically increasing,
# 2. audio timestamp is monotonically increasing,
# 3. video and audio timestamp is interleaved monotonically increasing.
# it's specified by RTMP specification, @see 3. Byte Order, Alignment, and Time Format
# however, some encoder cannot provides this feature, please set this to off to ignore time jitter.
# the time jitter algorithm:
# 1. full, to ensure stream start at zero, and ensure stream monotonically increasing.
# 2. zero, only ensure sttream start at zero, ignore timestamp jitter.
# 3. off, disable the time jitter algorithm, like atc.
# default: full
time_jitter full;
}
# vhost for atc.
vhost atc.srs.com {
# vhost for atc for hls/hds/rtmp backup.
... ...
... ... @@ -41,6 +41,7 @@ using namespace std;
#include <srs_kernel_log.hpp>
#include <srs_protocol_utility.hpp>
#include <srs_core_autofree.hpp>
#include <srs_app_source.hpp>
#define SRS_WIKI_URL_LOG "https://github.com/winlinvip/simple-rtmp-server/wiki/SrsLog"
... ... @@ -947,6 +948,17 @@ int SrsConfig::reload_vhost(SrsConfDirective* old_root)
}
srs_trace("vhost %s reload queue_length success.", vhost.c_str());
}
// time_jitter, only one per vhost
if (!srs_directive_equals(new_vhost->get("time_jitter"), old_vhost->get("time_jitter"))) {
for (it = subscribes.begin(); it != subscribes.end(); ++it) {
ISrsReloadHandler* subscribe = *it;
if ((ret = subscribe->on_reload_vhost_time_jitter(vhost)) != ERROR_SUCCESS) {
srs_error("vhost %s notify subscribes time_jitter failed. ret=%d", vhost.c_str(), ret);
return ret;
}
}
srs_trace("vhost %s reload time_jitter success.", vhost.c_str());
}
// forward, only one per vhost
if (!srs_directive_equals(new_vhost->get("forward"), old_vhost->get("forward"))) {
for (it = subscribes.begin(); it != subscribes.end(); ++it) {
... ... @@ -1788,6 +1800,23 @@ bool SrsConfig::get_atc_auto(string vhost)
return true;
}
int SrsConfig::get_time_jitter(string vhost)
{
SrsConfDirective* dvr = get_vhost(vhost);
std::string time_jitter = SRS_CONF_DEFAULT_TIME_JITTER;
if (dvr) {
SrsConfDirective* conf = dvr->get("time_jitter");
if (conf) {
time_jitter = conf->arg0();
}
}
return _srs_time_jitter_string2int(time_jitter);
}
double SrsConfig::get_queue_length(string vhost)
{
SrsConfDirective* conf = get_vhost(vhost);
... ... @@ -2636,6 +2665,23 @@ int SrsConfig::get_dvr_duration(string vhost)
return ::atoi(conf->arg0().c_str());
}
int SrsConfig::get_dvr_time_jitter(string vhost)
{
SrsConfDirective* dvr = get_dvr(vhost);
std::string time_jitter = SRS_CONF_DEFAULT_TIME_JITTER;
if (dvr) {
SrsConfDirective* conf = dvr->get("time_jitter");
if (conf) {
time_jitter = conf->arg0();
}
}
return _srs_time_jitter_string2int(time_jitter);
}
SrsConfDirective* SrsConfig::get_http_api()
{
return root->get("http_api");
... ...
... ... @@ -49,6 +49,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SRS_CONF_DEFAULT_DVR_PLAN_HSS "hss"
#define SRS_CONF_DEFAULT_DVR_PLAN SRS_CONF_DEFAULT_DVR_PLAN_SESSION
#define SRS_CONF_DEFAULT_DVR_DURATION 30
#define SRS_CONF_DEFAULT_TIME_JITTER "full"
// in ms, for HLS aac sync time.
#define SRS_CONF_DEFAULT_AAC_SYNC 100
// in ms, for HLS aac flush the audio
... ... @@ -200,6 +201,7 @@ public:
virtual bool get_gop_cache(std::string vhost);
virtual bool get_atc(std::string vhost);
virtual bool get_atc_auto(std::string vhost);
virtual int get_time_jitter(std::string vhost);
virtual double get_queue_length(std::string vhost);
virtual SrsConfDirective* get_forward(std::string vhost);
virtual SrsConfDirective* get_refer(std::string vhost);
... ... @@ -272,6 +274,7 @@ public:
virtual std::string get_dvr_path(std::string vhost);
virtual std::string get_dvr_plan(std::string vhost);
virtual int get_dvr_duration(std::string vhost);
virtual int get_dvr_time_jitter(std::string vhost);
// http api section
private:
virtual SrsConfDirective* get_http_api();
... ...
... ... @@ -70,10 +70,15 @@ SrsDvrPlan::SrsDvrPlan()
fs = new SrsFileStream();
enc = new SrsFlvEncoder();
segment = new SrsFlvSegment();
jitter_algorithm = SrsRtmpJitterAlgorithmOFF;
_srs_config->subscribe(this);
}
SrsDvrPlan::~SrsDvrPlan()
{
_srs_config->unsubscribe(this);
srs_freep(jitter);
srs_freep(fs);
srs_freep(enc);
... ... @@ -86,6 +91,8 @@ int SrsDvrPlan::initialize(SrsSource* source, SrsRequest* req)
_source = source;
_req = req;
jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_dvr_time_jitter(_req->vhost);
return ret;
}
... ... @@ -198,7 +205,7 @@ int SrsDvrPlan::on_audio(SrsSharedPtrMessage* audio)
return ret;
}
if ((jitter->correct(audio, 0, 0)) != ERROR_SUCCESS) {
if ((jitter->correct(audio, 0, 0, jitter_algorithm)) != ERROR_SUCCESS) {
return ret;
}
... ... @@ -240,7 +247,7 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* video)
srs_verbose("dvr video is key: %d", is_key_frame);
#endif
if ((jitter->correct(video, 0, 0)) != ERROR_SUCCESS) {
if ((jitter->correct(video, 0, 0, jitter_algorithm)) != ERROR_SUCCESS) {
return ret;
}
... ... @@ -256,6 +263,15 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* video)
return ret;
}
int SrsDvrPlan::on_reload_vhost_dvr(std::string vhost)
{
int ret = ERROR_SUCCESS;
jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_dvr_time_jitter(_req->vhost);
return ret;
}
int SrsDvrPlan::flv_open(string stream, string path)
{
int ret = ERROR_SUCCESS;
... ...
... ... @@ -42,6 +42,9 @@ class SrsSharedPtrMessage;
class SrsFileStream;
class SrsFlvEncoder;
#include <srs_app_source.hpp>
#include <srs_app_reload.hpp>
/**
* a piece of flv segment.
*/
... ... @@ -93,21 +96,23 @@ public:
* 2. reap flv: when to reap the flv and start new piece.
*/
// TODO: FIXME: the plan is too fat, refine me.
class SrsDvrPlan
class SrsDvrPlan : public ISrsReloadHandler
{
protected:
private:
/**
* the underlayer dvr stream.
* if close, the flv is reap and closed.
* if open, new flv file is crote.
*/
SrsFileStream* fs;
SrsFlvEncoder* enc;
bool dvr_enabled;
SrsSource* _source;
SrsRequest* _req;
SrsRtmpJitter* jitter;
SrsRtmpJitterAlgorithm jitter_algorithm;
protected:
SrsFlvSegment* segment;
SrsRequest* _req;
bool dvr_enabled;
SrsFileStream* fs;
public:
SrsDvrPlan();
virtual ~SrsDvrPlan();
... ... @@ -118,6 +123,9 @@ public:
virtual int on_meta_data(SrsOnMetaDataPacket* metadata);
virtual int on_audio(SrsSharedPtrMessage* audio);
virtual int on_video(SrsSharedPtrMessage* video);
// interface ISrsReloadHandler
public:
virtual int on_reload_vhost_dvr(std::string vhost);
protected:
virtual int flv_open(std::string stream, std::string path);
virtual int flv_close();
... ...
... ... @@ -162,7 +162,7 @@ int SrsForwarder::on_meta_data(SrsSharedPtrMessage* metadata)
{
int ret = ERROR_SUCCESS;
if ((ret = jitter->correct(metadata, 0, 0)) != ERROR_SUCCESS) {
if ((ret = jitter->correct(metadata, 0, 0, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) {
srs_freep(metadata);
return ret;
}
... ... @@ -178,7 +178,7 @@ int SrsForwarder::on_audio(SrsSharedPtrMessage* msg)
{
int ret = ERROR_SUCCESS;
if ((ret = jitter->correct(msg, 0, 0)) != ERROR_SUCCESS) {
if ((ret = jitter->correct(msg, 0, 0, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) {
srs_freep(msg);
return ret;
}
... ... @@ -194,7 +194,7 @@ int SrsForwarder::on_video(SrsSharedPtrMessage* msg)
{
int ret = ERROR_SUCCESS;
if ((ret = jitter->correct(msg, 0, 0)) != ERROR_SUCCESS) {
if ((ret = jitter->correct(msg, 0, 0, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) {
srs_freep(msg);
return ret;
}
... ...
... ... @@ -1411,7 +1411,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* audio)
return hls_cache->on_sequence_header(muxer);
}
if ((ret = jitter->correct(audio, 0, 0)) != ERROR_SUCCESS) {
if ((ret = jitter->correct(audio, 0, 0, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) {
srs_error("rtmp jitter correct audio failed. ret=%d", ret);
return ret;
}
... ... @@ -1456,7 +1456,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* video)
return hls_cache->on_sequence_header(muxer);
}
if ((ret = jitter->correct(video, 0, 0)) != ERROR_SUCCESS) {
if ((ret = jitter->correct(video, 0, 0, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) {
srs_error("rtmp jitter correct video failed. ret=%d", ret);
return ret;
}
... ...
... ... @@ -120,6 +120,11 @@ int ISrsReloadHandler::on_reload_vhost_queue_length(string /*vhost*/)
return ERROR_SUCCESS;
}
int ISrsReloadHandler::on_reload_vhost_time_jitter(string /*vhost*/)
{
return ERROR_SUCCESS;
}
int ISrsReloadHandler::on_reload_vhost_forward(string /*vhost*/)
{
return ERROR_SUCCESS;
... ...
... ... @@ -61,6 +61,7 @@ public:
virtual int on_reload_vhost_atc(std::string vhost);
virtual int on_reload_vhost_gop_cache(std::string vhost);
virtual int on_reload_vhost_queue_length(std::string vhost);
virtual int on_reload_vhost_time_jitter(std::string vhost);
virtual int on_reload_vhost_forward(std::string vhost);
virtual int on_reload_vhost_hls(std::string vhost);
virtual int on_reload_vhost_dvr(std::string vhost);
... ...
... ... @@ -45,6 +45,17 @@ using namespace std;
#define CONST_MAX_JITTER_MS 500
#define DEFAULT_FRAME_TIME_MS 40
int _srs_time_jitter_string2int(std::string time_jitter)
{
if (time_jitter == "full") {
return SrsRtmpJitterAlgorithmFULL;
} else if (time_jitter == "zero") {
return SrsRtmpJitterAlgorithmZERO;
} else {
return SrsRtmpJitterAlgorithmOFF;
}
}
SrsRtmpJitter::SrsRtmpJitter()
{
last_pkt_correct_time = last_pkt_time = 0;
... ... @@ -54,10 +65,27 @@ SrsRtmpJitter::~SrsRtmpJitter()
{
}
int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv)
int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, SrsRtmpJitterAlgorithm ag)
{
int ret = ERROR_SUCCESS;
// all jitter correct features is disabled, ignore.
if (ag == SrsRtmpJitterAlgorithmOFF) {
return ret;
}
// start at zero, but donot ensure monotonically increasing.
if (ag == SrsRtmpJitterAlgorithmZERO) {
if (last_pkt_correct_time <= 0) {
last_pkt_correct_time = msg->header.timestamp;
}
msg->header.timestamp -= last_pkt_correct_time;
return ret;
}
// full jitter algorithm, do jitter correct.
// set to 0 for metadata.
if (!msg->header.is_video() && !msg->header.is_audio()) {
msg->header.timestamp = 0;
... ... @@ -266,12 +294,12 @@ int SrsConsumer::get_time()
return jitter->get_time();
}
int SrsConsumer::enqueue(SrsSharedPtrMessage* msg, bool atc, int tba, int tbv)
int SrsConsumer::enqueue(SrsSharedPtrMessage* msg, bool atc, int tba, int tbv, SrsRtmpJitterAlgorithm ag)
{
int ret = ERROR_SUCCESS;
if (!atc) {
if ((ret = jitter->correct(msg, tba, tbv)) != ERROR_SUCCESS) {
if ((ret = jitter->correct(msg, tba, tbv, ag)) != ERROR_SUCCESS) {
srs_freep(msg);
return ret;
}
... ... @@ -384,7 +412,7 @@ void SrsGopCache::clear()
cached_video_count = 0;
}
int SrsGopCache::dump(SrsConsumer* consumer, bool atc, int tba, int tbv)
int SrsGopCache::dump(SrsConsumer* consumer, bool atc, int tba, int tbv, SrsRtmpJitterAlgorithm jitter_algorithm)
{
int ret = ERROR_SUCCESS;
... ... @@ -392,7 +420,7 @@ int SrsGopCache::dump(SrsConsumer* consumer, bool atc, int tba, int tbv)
for (it = gop_cache.begin(); it != gop_cache.end(); ++it) {
SrsSharedPtrMessage* msg = *it;
SrsSharedPtrMessage* copy = msg->copy();
if ((ret = consumer->enqueue(copy, atc, tba, tbv)) != ERROR_SUCCESS) {
if ((ret = consumer->enqueue(copy, atc, tba, tbv, jitter_algorithm)) != ERROR_SUCCESS) {
srs_error("dispatch cached gop failed. ret=%d", ret);
return ret;
}
... ... @@ -464,6 +492,7 @@ void SrsSource::destroy()
SrsSource::SrsSource(SrsRequest* req)
{
_req = req->copy();
jitter_algorithm = SrsRtmpJitterAlgorithmOFF;
#ifdef SRS_AUTO_HLS
hls = new SrsHls(this);
... ... @@ -549,6 +578,8 @@ int SrsSource::initialize()
double queue_size = _srs_config->get_queue_length(_req->vhost);
publish_edge->set_queue_size(queue_size);
jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_time_jitter(_req->vhost);
return ret;
}
... ... @@ -630,6 +661,19 @@ int SrsSource::on_reload_vhost_queue_length(string vhost)
return ret;
}
int SrsSource::on_reload_vhost_time_jitter(string vhost)
{
int ret = ERROR_SUCCESS;
if (_req->vhost != vhost) {
return ret;
}
jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_time_jitter(_req->vhost);
return ret;
}
int SrsSource::on_reload_vhost_forward(string vhost)
{
int ret = ERROR_SUCCESS;
... ... @@ -928,7 +972,7 @@ int SrsSource::on_meta_data(SrsMessage* msg, SrsOnMetaDataPacket* metadata)
for (it = consumers.begin(); it != consumers.end(); ++it) {
SrsConsumer* consumer = *it;
SrsSharedPtrMessage* copy = cache_metadata->copy();
if ((ret = consumer->enqueue(copy, atc, sample_rate, frame_rate)) != ERROR_SUCCESS) {
if ((ret = consumer->enqueue(copy, atc, sample_rate, frame_rate, jitter_algorithm)) != ERROR_SUCCESS) {
srs_error("dispatch the metadata failed. ret=%d", ret);
return ret;
}
... ... @@ -992,7 +1036,7 @@ int SrsSource::on_audio(SrsMessage* audio)
for (int i = 0; i < (int)consumers.size(); i++) {
SrsConsumer* consumer = consumers.at(i);
SrsSharedPtrMessage* copy = msg->copy();
if ((ret = consumer->enqueue(copy, atc, sample_rate, frame_rate)) != ERROR_SUCCESS) {
if ((ret = consumer->enqueue(copy, atc, sample_rate, frame_rate, jitter_algorithm)) != ERROR_SUCCESS) {
srs_error("dispatch the audio failed. ret=%d", ret);
return ret;
}
... ... @@ -1082,7 +1126,7 @@ int SrsSource::on_video(SrsMessage* video)
for (int i = 0; i < (int)consumers.size(); i++) {
SrsConsumer* consumer = consumers.at(i);
SrsSharedPtrMessage* copy = msg->copy();
if ((ret = consumer->enqueue(copy, atc, sample_rate, frame_rate)) != ERROR_SUCCESS) {
if ((ret = consumer->enqueue(copy, atc, sample_rate, frame_rate, jitter_algorithm)) != ERROR_SUCCESS) {
srs_error("dispatch the video failed. ret=%d", ret);
return ret;
}
... ... @@ -1328,28 +1372,32 @@ void SrsSource::on_unpublish()
}
}
int tba = sample_rate;
int tbv = frame_rate;
SrsRtmpJitterAlgorithm ag = jitter_algorithm;
// copy metadata.
if (cache_metadata && (ret = consumer->enqueue(cache_metadata->copy(), atc, sample_rate, frame_rate)) != ERROR_SUCCESS) {
if (cache_metadata && (ret = consumer->enqueue(cache_metadata->copy(), atc, tba, tbv, ag)) != ERROR_SUCCESS) {
srs_error("dispatch metadata failed. ret=%d", ret);
return ret;
}
srs_info("dispatch metadata success");
// copy sequence header
if (cache_sh_video && (ret = consumer->enqueue(cache_sh_video->copy(), atc, sample_rate, frame_rate)) != ERROR_SUCCESS) {
if (cache_sh_video && (ret = consumer->enqueue(cache_sh_video->copy(), atc, tba, tbv, ag)) != ERROR_SUCCESS) {
srs_error("dispatch video sequence header failed. ret=%d", ret);
return ret;
}
srs_info("dispatch video sequence header success");
if (cache_sh_audio && (ret = consumer->enqueue(cache_sh_audio->copy(), atc, sample_rate, frame_rate)) != ERROR_SUCCESS) {
if (cache_sh_audio && (ret = consumer->enqueue(cache_sh_audio->copy(), atc, tba, tbv, ag)) != ERROR_SUCCESS) {
srs_error("dispatch audio sequence header failed. ret=%d", ret);
return ret;
}
srs_info("dispatch audio sequence header success");
// copy gop cache to client.
if ((ret = gop_cache->dump(consumer, atc, sample_rate, frame_rate)) != ERROR_SUCCESS) {
if ((ret = gop_cache->dump(consumer, atc, tba, tbv, ag)) != ERROR_SUCCESS) {
return ret;
}
... ...
... ... @@ -60,6 +60,20 @@ class SrsEncoder;
class SrsStream;
/**
* the time jitter algorithm:
* 1. full, to ensure stream start at zero, and ensure stream monotonically increasing.
* 2. zero, only ensure sttream start at zero, ignore timestamp jitter.
* 3. off, disable the time jitter algorithm, like atc.
*/
enum SrsRtmpJitterAlgorithm
{
SrsRtmpJitterAlgorithmFULL = 0x01,
SrsRtmpJitterAlgorithmZERO,
SrsRtmpJitterAlgorithmOFF
};
int _srs_time_jitter_string2int(std::string time_jitter);
/**
* time jitter detect and correct,
* to ensure the rtmp stream is monotonically.
*/
... ... @@ -74,8 +88,12 @@ public:
public:
/**
* detect the time jitter and correct it.
* @param tba, the audio timebase, used to calc the "right" delta if jitter detected.
* @param tbv, the video timebase, used to calc the "right" delta if jitter detected.
* @param start_at_zero whether ensure stream start at zero.
* @param mono_increasing whether ensure stream is monotonically inscreasing.
*/
virtual int correct(SrsSharedPtrMessage* msg, int tba, int tbv);
virtual int correct(SrsSharedPtrMessage* msg, int tba, int tbv, SrsRtmpJitterAlgorithm ag);
/**
* get current client time, the last packet time.
*/
... ... @@ -160,8 +178,9 @@ public:
* used to calc the audio time delta if time-jitter detected.
* @param tbv timebase of video.
* used to calc the video time delta if time-jitter detected.
* @param ag the algorithm of time jitter.
*/
virtual int enqueue(SrsSharedPtrMessage* msg, bool atc, int tba, int tbv);
virtual int enqueue(SrsSharedPtrMessage* msg, bool atc, int tba, int tbv, SrsRtmpJitterAlgorithm ag);
/**
* get packets in consumer queue.
* @pmsgs SrsMessages*[], used to store the msgs, user must alloc it.
... ... @@ -209,7 +228,7 @@ public:
*/
virtual int cache(SrsSharedPtrMessage* msg);
virtual void clear();
virtual int dump(SrsConsumer* consumer, bool atc, int tba, int tbv);
virtual int dump(SrsConsumer* consumer, bool atc, int tba, int tbv, SrsRtmpJitterAlgorithm jitter_algorithm);
/**
* used for atc to get the time of gop cache,
* the atc will adjust the sequence header timestamp to gop cache.
... ... @@ -249,6 +268,8 @@ private:
SrsRequest* _req;
// to delivery stream to clients.
std::vector<SrsConsumer*> consumers;
// the time jitter algorithm for vhost.
SrsRtmpJitterAlgorithm jitter_algorithm;
// hls handler.
#ifdef SRS_AUTO_HLS
SrsHls* hls;
... ... @@ -310,6 +331,7 @@ public:
virtual int on_reload_vhost_atc(std::string vhost);
virtual int on_reload_vhost_gop_cache(std::string vhost);
virtual int on_reload_vhost_queue_length(std::string vhost);
virtual int on_reload_vhost_time_jitter(std::string vhost);
virtual int on_reload_vhost_forward(std::string vhost);
virtual int on_reload_vhost_hls(std::string vhost);
virtual int on_reload_vhost_dvr(std::string vhost);
... ...
... ... @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// current release version
#define VERSION_MAJOR "0"
#define VERSION_MINOR "9"
#define VERSION_REVISION "132"
#define VERSION_REVISION "133"
#define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
// server info.
#define RTMP_SIG_SRS_KEY "SRS"
... ...