mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Merge code.
Conflicts: trunk/configure trunk/src/app/srs_app_source.cpp trunk/src/kernel/srs_kernel_error.hpp
This commit is contained in:
commit
e57bda8908
90 changed files with 4584 additions and 3576 deletions
|
@ -1419,7 +1419,6 @@ int SrsConfig::check_config()
|
|||
string m = conf->at(j)->name.c_str();
|
||||
if (m != "enabled" && m != "dvr_path" && m != "dvr_plan"
|
||||
&& m != "dvr_duration" && m != "dvr_wait_keyframe" && m != "time_jitter"
|
||||
&& m != "dvr_autostart"
|
||||
) {
|
||||
ret = ERROR_SYSTEM_CONFIG_INVALID;
|
||||
srs_error("unsupported vhost dvr directive %s, ret=%d", m.c_str(), ret);
|
||||
|
@ -1978,38 +1977,6 @@ int SrsConfig::get_stream_caster_rtp_port_max(SrsConfDirective* sc)
|
|||
return ::atoi(conf->arg0().c_str());
|
||||
}
|
||||
|
||||
SrsConfDirective* SrsConfig::create_directive(string vhost, string directive, string sub_directive)
|
||||
{
|
||||
SrsConfDirective* vhost_conf = get_vhost(vhost);
|
||||
|
||||
if (!vhost_conf) {
|
||||
vhost_conf = new SrsConfDirective();
|
||||
root->directives.push_back(vhost_conf);
|
||||
}
|
||||
|
||||
if (directive.empty()) {
|
||||
return vhost_conf;
|
||||
}
|
||||
|
||||
SrsConfDirective* dir = vhost_conf->get(directive);
|
||||
if (!dir) {
|
||||
dir = new SrsConfDirective();
|
||||
vhost_conf->directives.push_back(dir);
|
||||
}
|
||||
|
||||
if (sub_directive.empty()) {
|
||||
return dir;
|
||||
}
|
||||
|
||||
SrsConfDirective* sdir = dir->get(sub_directive);
|
||||
if (!sdir) {
|
||||
sdir = new SrsConfDirective();
|
||||
dir->directives.push_back(sdir);
|
||||
}
|
||||
|
||||
return sdir;
|
||||
}
|
||||
|
||||
SrsConfDirective* SrsConfig::get_vhost(string vhost)
|
||||
{
|
||||
srs_assert(root);
|
||||
|
@ -3422,13 +3389,6 @@ bool SrsConfig::get_dvr_enabled(string vhost)
|
|||
return false;
|
||||
}
|
||||
|
||||
void SrsConfig::set_dvr_enabled(string vhost, bool enabled)
|
||||
{
|
||||
SrsConfDirective* conf = create_directive(vhost, "dvr", "enabled");
|
||||
conf->args.clear();
|
||||
conf->args.push_back(enabled? "on":"off");
|
||||
}
|
||||
|
||||
string SrsConfig::get_dvr_path(string vhost)
|
||||
{
|
||||
SrsConfDirective* dvr = get_dvr(vhost);
|
||||
|
@ -3446,13 +3406,6 @@ string SrsConfig::get_dvr_path(string vhost)
|
|||
return conf->arg0();
|
||||
}
|
||||
|
||||
void SrsConfig::set_dvr_path(string vhost, string path)
|
||||
{
|
||||
SrsConfDirective* conf = create_directive(vhost, "dvr", "dvr_path");
|
||||
conf->args.clear();
|
||||
conf->args.push_back(path);
|
||||
}
|
||||
|
||||
string SrsConfig::get_dvr_plan(string vhost)
|
||||
{
|
||||
SrsConfDirective* dvr = get_dvr(vhost);
|
||||
|
@ -3504,30 +3457,6 @@ bool SrsConfig::get_dvr_wait_keyframe(string vhost)
|
|||
return false;
|
||||
}
|
||||
|
||||
void SrsConfig::set_dvr_wait_keyframe(string vhost, bool wait_keyframe)
|
||||
{
|
||||
SrsConfDirective* conf = create_directive(vhost, "dvr", "dvr_wait_keyframe");
|
||||
conf->args.clear();
|
||||
conf->args.push_back(wait_keyframe? "on":"off");
|
||||
}
|
||||
|
||||
bool SrsConfig::get_dvr_autostart(string vhost)
|
||||
{
|
||||
SrsConfDirective* dvr = get_dvr(vhost);
|
||||
|
||||
if (!dvr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SrsConfDirective* conf = dvr->get("dvr_autostart");
|
||||
|
||||
if (!conf || conf->arg0() != "off") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int SrsConfig::get_dvr_time_jitter(string vhost)
|
||||
{
|
||||
SrsConfDirective* dvr = get_dvr(vhost);
|
||||
|
|
|
@ -61,7 +61,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#define SRS_CONF_DEFAULT_DVR_PLAN_SESSION "session"
|
||||
#define SRS_CONF_DEFAULT_DVR_PLAN_SEGMENT "segment"
|
||||
#define SRS_CONF_DEFAULT_DVR_PLAN_APPEND "append"
|
||||
#define SRS_CONF_DEFAULT_DVR_PLAN_API "api"
|
||||
#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"
|
||||
|
@ -357,11 +356,11 @@ private:
|
|||
* print help and exit.
|
||||
*/
|
||||
virtual void print_help(char** argv);
|
||||
public:
|
||||
/**
|
||||
* parse the config file, which is specified by cli.
|
||||
*/
|
||||
virtual int parse_file(const char* filename);
|
||||
public:
|
||||
/**
|
||||
* check the parsed config.
|
||||
*/
|
||||
|
@ -457,14 +456,6 @@ public:
|
|||
* get the max udp port for rtp of stream caster rtsp.
|
||||
*/
|
||||
virtual int get_stream_caster_rtp_port_max(SrsConfDirective* sc);
|
||||
private:
|
||||
/**
|
||||
* create directive under vhost.
|
||||
* @param directive, get the directive of vhost. get vhost if directive is empty.
|
||||
* @param sub_directive, get the sub directive of vhost. get directive if sub-directive is empty.
|
||||
* @return the vhost(empty directive and sub-directive); the directive(empty sub-directive); the sub-directive.
|
||||
*/
|
||||
virtual SrsConfDirective* create_directive(std::string vhost, std::string directive, std::string sub_directive);
|
||||
// vhost specified section
|
||||
public:
|
||||
/**
|
||||
|
@ -954,12 +945,10 @@ public:
|
|||
* whether dvr is enabled.
|
||||
*/
|
||||
virtual bool get_dvr_enabled(std::string vhost);
|
||||
virtual void set_dvr_enabled(std::string vhost, bool enabled);
|
||||
/**
|
||||
* get the dvr path, the flv file to save in.
|
||||
*/
|
||||
virtual std::string get_dvr_path(std::string vhost);
|
||||
virtual void set_dvr_path(std::string vhost, std::string path);
|
||||
/**
|
||||
* get the plan of dvr, how to reap the flv file.
|
||||
*/
|
||||
|
@ -972,11 +961,6 @@ public:
|
|||
* whether wait keyframe to reap segment.
|
||||
*/
|
||||
virtual bool get_dvr_wait_keyframe(std::string vhost);
|
||||
virtual void set_dvr_wait_keyframe(std::string vhost, bool wait_keyframe);
|
||||
/**
|
||||
* whether autostart for dvr. wait api to start dvr if false.
|
||||
*/
|
||||
virtual bool get_dvr_autostart(std::string vhost);
|
||||
/**
|
||||
* get the time_jitter algorithm for dvr.
|
||||
*/
|
||||
|
@ -1148,3 +1132,4 @@ bool srs_directive_equals(SrsConfDirective* a, SrsConfDirective* b);
|
|||
extern SrsConfig* _srs_config;
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
SrsConnection::SrsConnection(SrsServer* srs_server, st_netfd_t client_stfd)
|
||||
{
|
||||
id = 0;
|
||||
server = srs_server;
|
||||
stfd = client_stfd;
|
||||
|
||||
|
@ -55,6 +56,8 @@ int SrsConnection::cycle()
|
|||
int ret = ERROR_SUCCESS;
|
||||
|
||||
_srs_context->generate_id();
|
||||
id = _srs_context->get_id();
|
||||
|
||||
ip = srs_get_peer_ip(st_netfd_fileno(stfd));
|
||||
|
||||
ret = do_cycle();
|
||||
|
@ -86,6 +89,11 @@ void SrsConnection::on_thread_stop()
|
|||
server->remove(this);
|
||||
}
|
||||
|
||||
int SrsConnection::srs_id()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
void SrsConnection::stop()
|
||||
{
|
||||
srs_close_stfd(stfd);
|
||||
|
|
|
@ -51,6 +51,10 @@ private:
|
|||
* when thread stop, the connection will be delete by server.
|
||||
*/
|
||||
SrsThread* pthread;
|
||||
/**
|
||||
* the id of connection.
|
||||
*/
|
||||
int id;
|
||||
protected:
|
||||
/**
|
||||
* the server object to manage the connection.
|
||||
|
@ -92,13 +96,9 @@ public:
|
|||
virtual void on_thread_stop();
|
||||
public:
|
||||
/**
|
||||
* when server to get the kbps of connection,
|
||||
* it cannot wait the connection terminated then get the kbps,
|
||||
* it must sample the kbps every some interval, for instance, 9s to sample all connections kbps,
|
||||
* all connections will extends from IKbpsDelta which provides the bytes delta,
|
||||
* while the delta must be update by the sample which invoke by the kbps_resample().
|
||||
* get the srs id which identify the client.
|
||||
*/
|
||||
virtual void kbps_resample() = 0;
|
||||
virtual int srs_id();
|
||||
protected:
|
||||
/**
|
||||
* for concrete connection to do the cycle.
|
||||
|
|
|
@ -28,6 +28,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#include <fcntl.h>
|
||||
#include <sstream>
|
||||
#include <sys/time.h>
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
#include <srs_app_config.hpp>
|
||||
|
@ -54,7 +55,6 @@ using namespace std;
|
|||
SrsFlvSegment::SrsFlvSegment(SrsDvrPlan* p)
|
||||
{
|
||||
req = NULL;
|
||||
source = NULL;
|
||||
jitter = NULL;
|
||||
plan = p;
|
||||
|
||||
|
@ -85,11 +85,10 @@ SrsFlvSegment::~SrsFlvSegment()
|
|||
srs_freep(enc);
|
||||
}
|
||||
|
||||
int SrsFlvSegment::initialize(SrsSource* s, SrsRequest* r)
|
||||
int SrsFlvSegment::initialize(SrsRequest* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
source = s;
|
||||
req = r;
|
||||
jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_dvr_time_jitter(req->vhost);
|
||||
|
||||
|
@ -308,10 +307,10 @@ int SrsFlvSegment::write_video(SrsSharedPtrMessage* __video)
|
|||
char* payload = video->payload;
|
||||
int size = video->size;
|
||||
|
||||
bool is_sequence_header = SrsFlvCodec::video_is_sequence_header(payload, size);
|
||||
#ifdef SRS_AUTO_HTTP_CALLBACK
|
||||
bool is_key_frame = SrsFlvCodec::video_is_h264(payload, size)
|
||||
&& SrsFlvCodec::video_is_keyframe(payload, size)
|
||||
&& !SrsFlvCodec::video_is_sequence_header(payload, size);
|
||||
&& SrsFlvCodec::video_is_keyframe(payload, size) && !is_sequence_header;
|
||||
if (is_key_frame) {
|
||||
has_keyframe = true;
|
||||
if ((ret = plan->on_video_keyframe()) != ERROR_SUCCESS) {
|
||||
|
@ -320,6 +319,16 @@ int SrsFlvSegment::write_video(SrsSharedPtrMessage* __video)
|
|||
}
|
||||
srs_verbose("dvr video is key: %d", is_key_frame);
|
||||
#endif
|
||||
|
||||
// accept the sequence header here.
|
||||
// when got no keyframe, ignore when should wait keyframe.
|
||||
if (!has_keyframe && !is_sequence_header) {
|
||||
bool wait_keyframe = _srs_config->get_dvr_wait_keyframe(req->vhost);
|
||||
if (wait_keyframe) {
|
||||
srs_info("dvr: ignore when wait keyframe.");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if ((jitter->correct(video, 0, 0, jitter_algorithm)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
|
@ -617,48 +626,6 @@ string SrsDvrAsyncCallOnDvr::to_string()
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
SrsDvrAsyncCallOnSegment::SrsDvrAsyncCallOnSegment(SrsRequest* r, string c, string p)
|
||||
{
|
||||
req = r;
|
||||
callback = c;
|
||||
path = p;
|
||||
}
|
||||
|
||||
SrsDvrAsyncCallOnSegment::~SrsDvrAsyncCallOnSegment()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsDvrAsyncCallOnSegment::call()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
#ifdef SRS_AUTO_HTTP_CALLBACK
|
||||
// HTTP: callback
|
||||
if (callback.empty()) {
|
||||
srs_warn("dvr: ignore for callback empty, vhost=%s", req->vhost.c_str());
|
||||
return ret;
|
||||
}
|
||||
|
||||
int connection_id = _srs_context->get_id();
|
||||
std::string cwd = _srs_config->cwd();
|
||||
std::string file = path;
|
||||
std::string url = callback;
|
||||
if ((ret = SrsHttpHooks::on_dvr_reap_segment(url, connection_id, req, cwd, file)) != ERROR_SUCCESS) {
|
||||
srs_error("hook client on_dvr_reap_segment failed. url=%s, ret=%d", url.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
string SrsDvrAsyncCallOnSegment::to_string()
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "vhost=" << req->vhost << ", file=" << path << "callback=" << callback;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
SrsDvrAsyncCallThread::SrsDvrAsyncCallThread()
|
||||
{
|
||||
pthread = new SrsThread("async", this, SRS_AUTO_ASYNC_CALLBACL_SLEEP_US, true);
|
||||
|
@ -717,7 +684,6 @@ int SrsDvrAsyncCallThread::cycle()
|
|||
|
||||
SrsDvrPlan::SrsDvrPlan()
|
||||
{
|
||||
source = NULL;
|
||||
req = NULL;
|
||||
|
||||
dvr_enabled = false;
|
||||
|
@ -731,14 +697,13 @@ SrsDvrPlan::~SrsDvrPlan()
|
|||
srs_freep(async);
|
||||
}
|
||||
|
||||
int SrsDvrPlan::initialize(SrsSource* s, SrsRequest* r)
|
||||
int SrsDvrPlan::initialize(SrsRequest* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
source = s;
|
||||
|
||||
req = r;
|
||||
|
||||
if ((ret = segment->initialize(s, r)) != ERROR_SUCCESS) {
|
||||
if ((ret = segment->initialize(r)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -749,18 +714,6 @@ int SrsDvrPlan::initialize(SrsSource* s, SrsRequest* r)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrPlan::on_dvr_request_sh()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// the dvr is enabled, notice the source to push the data.
|
||||
if ((ret = source->on_dvr_request_sh()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrPlan::on_video_keyframe()
|
||||
{
|
||||
return ERROR_SUCCESS;
|
||||
|
@ -832,8 +785,6 @@ SrsDvrPlan* SrsDvrPlan::create_plan(string vhost)
|
|||
return new SrsDvrSessionPlan();
|
||||
} else if (plan == SRS_CONF_DEFAULT_DVR_PLAN_APPEND) {
|
||||
return new SrsDvrAppendPlan();
|
||||
} else if (plan == SRS_CONF_DEFAULT_DVR_PLAN_API) {
|
||||
return new SrsDvrApiPlan();
|
||||
} else {
|
||||
srs_error("invalid dvr plan=%s, vhost=%s", plan.c_str(), vhost.c_str());
|
||||
srs_assert(false);
|
||||
|
@ -890,320 +841,6 @@ void SrsDvrSessionPlan::on_unpublish()
|
|||
dvr_enabled = false;
|
||||
}
|
||||
|
||||
SrsDvrApiPlan::SrsDvrApiPlan()
|
||||
{
|
||||
autostart = false;
|
||||
started = false;
|
||||
|
||||
metadata = sh_audio = sh_video = NULL;
|
||||
}
|
||||
|
||||
SrsDvrApiPlan::~SrsDvrApiPlan()
|
||||
{
|
||||
srs_freep(metadata);
|
||||
srs_freep(sh_audio);
|
||||
srs_freep(sh_video);
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::initialize(SrsSource* s, SrsRequest* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if ((ret = SrsDvrPlan::initialize(s, r)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsApiDvrPool* pool = SrsApiDvrPool::instance();
|
||||
if ((ret = pool->add_dvr(this)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
autostart = _srs_config->get_dvr_autostart(r->vhost);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::on_publish()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// support multiple publish.
|
||||
if (dvr_enabled) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!_srs_config->get_dvr_enabled(req->vhost)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// api disabled dvr when not autostart.
|
||||
bool autostart = _srs_config->get_dvr_autostart(req->vhost);
|
||||
if (!autostart && !started) {
|
||||
srs_warn("dvr: api not start and disabled for not autostart.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dvr_enabled = true;
|
||||
|
||||
if ((ret = segment->close()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = segment->open()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// update sequence header
|
||||
if (metadata && (ret = SrsDvrPlan::on_meta_data(metadata)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if (sh_video && (ret = SrsDvrPlan::on_video(sh_video)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if (sh_audio && (ret = SrsDvrPlan::on_audio(sh_audio)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SrsDvrApiPlan::on_unpublish()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::on_meta_data(SrsSharedPtrMessage* __metadata)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
srs_freep(metadata);
|
||||
metadata = __metadata->copy();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::on_audio(SrsSharedPtrMessage* __audio)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (SrsFlvCodec::audio_is_sequence_header(__audio->payload, __audio->size)) {
|
||||
srs_freep(sh_audio);
|
||||
sh_audio = __audio->copy();
|
||||
}
|
||||
|
||||
if ((ret = SrsDvrPlan::on_audio(__audio)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::on_video(SrsSharedPtrMessage* __video)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (SrsFlvCodec::video_is_sequence_header(__video->payload, __video->size)) {
|
||||
srs_freep(sh_video);
|
||||
sh_video = __video->copy();
|
||||
}
|
||||
|
||||
if ((ret = check_user_actions(__video)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = SrsDvrPlan::on_video(__video)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::set_path_tmpl(string path_tmpl)
|
||||
{
|
||||
_srs_config->set_dvr_path(req->vhost, path_tmpl);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::set_callback(string value)
|
||||
{
|
||||
callback = value;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::set_wait_keyframe(bool wait_keyframe)
|
||||
{
|
||||
_srs_config->set_dvr_wait_keyframe(req->vhost, wait_keyframe);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::start()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (started) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// enable the config.
|
||||
_srs_config->set_dvr_enabled(req->vhost, true);
|
||||
|
||||
// stop dvr
|
||||
if (dvr_enabled) {
|
||||
// ignore error.
|
||||
int ret = segment->close();
|
||||
if (ret != ERROR_SUCCESS) {
|
||||
srs_warn("ignore flv close error. ret=%d", ret);
|
||||
}
|
||||
|
||||
dvr_enabled = false;
|
||||
}
|
||||
|
||||
// start dvr
|
||||
if ((ret = on_publish()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
started = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::dumps(stringstream& ss)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
bool wait_keyframe = _srs_config->get_dvr_wait_keyframe(req->vhost);
|
||||
std::string path_template = _srs_config->get_dvr_path(req->vhost);
|
||||
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_STR("path_tmpl", path_template) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("path_dvr", segment->get_path()) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_BOOL("wait_keyframe", wait_keyframe) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("callback", callback) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("status", (dvr_enabled? "start":"stop"))
|
||||
<< __SRS_JOBJECT_END;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::stop()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
_srs_config->set_dvr_enabled(req->vhost, false);
|
||||
started = false;
|
||||
|
||||
// stop dvr
|
||||
if (dvr_enabled) {
|
||||
// ignore error.
|
||||
int ret = segment->close();
|
||||
if (ret != ERROR_SUCCESS) {
|
||||
srs_warn("ignore flv close error. ret=%d", ret);
|
||||
}
|
||||
|
||||
dvr_enabled = false;
|
||||
}
|
||||
|
||||
srs_trace("dvr: stop dvr of vhost=%s", req->vhost.c_str());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::rpc(SrsJsonObject* obj)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
SrsJsonAny* prop = NULL;
|
||||
if ((prop = obj->ensure_property_string("action")) == NULL) {
|
||||
ret = ERROR_HTTP_DVR_REQUEST;
|
||||
srs_error("dvr: rpc required action request. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
action = prop->to_str();
|
||||
if (action == SRS_DVR_USER_ACTION_REAP_SEGMENT) {
|
||||
if ((prop = obj->ensure_property_string("path_tmpl")) != NULL) {
|
||||
path_template = prop->to_str();
|
||||
}
|
||||
} else {
|
||||
ret = ERROR_HTTP_DVR_REQUEST;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::on_reap_segment()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if ((ret = SrsDvrPlan::on_reap_segment()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = async->call(new SrsDvrAsyncCallOnSegment(req, callback, segment->get_path()))) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::check_user_actions(SrsSharedPtrMessage* msg)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
srs_assert(segment);
|
||||
|
||||
if (action == SRS_DVR_USER_ACTION_REAP_SEGMENT) {
|
||||
// when wait keyframe, ignore if no frame arrived.
|
||||
// @see https://github.com/winlinvip/simple-rtmp-server/issues/177
|
||||
if (_srs_config->get_dvr_wait_keyframe(req->vhost)) {
|
||||
if (!msg->is_video()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* payload = msg->payload;
|
||||
int size = msg->size;
|
||||
bool is_key_frame = SrsFlvCodec::video_is_h264(payload, size)
|
||||
&& SrsFlvCodec::video_is_keyframe(payload, size)
|
||||
&& !SrsFlvCodec::video_is_sequence_header(payload, size);
|
||||
if (!is_key_frame) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
// reap segment
|
||||
if ((ret = segment->close()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// use new path template if user specified.
|
||||
if (!path_template.empty() && (ret = set_path_tmpl(path_template)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// open new flv file
|
||||
if ((ret = segment->open()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// update sequence header
|
||||
if (metadata && (ret = SrsDvrPlan::on_meta_data(metadata)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if (sh_video && (ret = SrsDvrPlan::on_video(sh_video)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if (sh_audio && (ret = SrsDvrPlan::on_audio(sh_audio)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
// reset rcp params.
|
||||
action = "";
|
||||
path_template = "";
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsDvrAppendPlan::SrsDvrAppendPlan()
|
||||
{
|
||||
last_update_time = 0;
|
||||
|
@ -1309,11 +946,11 @@ SrsDvrSegmentPlan::~SrsDvrSegmentPlan()
|
|||
srs_freep(metadata);
|
||||
}
|
||||
|
||||
int SrsDvrSegmentPlan::initialize(SrsSource* source, SrsRequest* req)
|
||||
int SrsDvrSegmentPlan::initialize(SrsRequest* req)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if ((ret = SrsDvrPlan::initialize(source, req)) != ERROR_SUCCESS) {
|
||||
if ((ret = SrsDvrPlan::initialize(req)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1460,183 +1097,9 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
SrsApiDvrPool* SrsApiDvrPool::_instance = new SrsApiDvrPool();
|
||||
|
||||
SrsApiDvrPool* SrsApiDvrPool::instance()
|
||||
SrsDvr::SrsDvr()
|
||||
{
|
||||
return SrsApiDvrPool::_instance;
|
||||
}
|
||||
|
||||
SrsApiDvrPool::SrsApiDvrPool()
|
||||
{
|
||||
}
|
||||
|
||||
SrsApiDvrPool::~SrsApiDvrPool()
|
||||
{
|
||||
dvrs.clear();
|
||||
}
|
||||
|
||||
int SrsApiDvrPool::add_dvr(SrsDvrApiPlan* dvr)
|
||||
{
|
||||
dvrs.push_back(dvr);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int SrsApiDvrPool::dumps(string vhost, stringstream& ss)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
ss << __SRS_JARRAY_START;
|
||||
|
||||
std::vector<SrsDvrApiPlan*> plans;
|
||||
for (int i = 0; i < (int)dvrs.size(); i++) {
|
||||
SrsDvrApiPlan* plan = dvrs.at(i);
|
||||
if (!vhost.empty() && plan->req->vhost != vhost) {
|
||||
continue;
|
||||
}
|
||||
plans.push_back(plan);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)plans.size(); i++) {
|
||||
SrsDvrApiPlan* plan = plans.at(i);
|
||||
|
||||
if ((ret = plan->dumps(ss)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (i < (int)dvrs.size() - 1) {
|
||||
ss << __SRS_JFIELD_CONT;
|
||||
}
|
||||
}
|
||||
|
||||
ss << __SRS_JARRAY_END;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsApiDvrPool::create(SrsJsonAny* json)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
srs_assert(json);
|
||||
if (!json->is_object()) {
|
||||
ret = ERROR_HTTP_DVR_CREATE_REQUEST;
|
||||
srs_error("dvr: api create dvr request requires json object. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsJsonObject* obj = json->to_object();
|
||||
SrsJsonAny* prop = NULL;
|
||||
if ((prop = obj->ensure_property_string("vhost")) == NULL) {
|
||||
ret = ERROR_HTTP_DVR_CREATE_REQUEST;
|
||||
srs_error("dvr: api create dvr request requires vhost. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string vhost = prop->to_str();
|
||||
SrsDvrApiPlan* dvr = NULL;
|
||||
for (int i = 0; i < (int)dvrs.size(); i++) {
|
||||
SrsDvrApiPlan* plan = dvrs.at(i);
|
||||
if (!vhost.empty() && plan->req->vhost != vhost) {
|
||||
continue;
|
||||
}
|
||||
dvr = plan;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!dvr) {
|
||||
ret = ERROR_HTTP_DVR_CREATE_REQUEST;
|
||||
srs_error("dvr: api create dvr request vhost invalid. vhost=%s. ret=%d", vhost.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// update optional parameters for plan.
|
||||
if ((prop = obj->ensure_property_string("path_tmpl")) != NULL) {
|
||||
if ((ret = dvr->set_path_tmpl(prop->to_str())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if ((prop = obj->ensure_property_boolean("wait_keyframe")) != NULL) {
|
||||
if ((ret = dvr->set_wait_keyframe(prop->to_boolean())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if ((prop = obj->ensure_property_string("callback")) != NULL) {
|
||||
if ((ret = dvr->set_callback(prop->to_str())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return dvr->start();
|
||||
}
|
||||
|
||||
int SrsApiDvrPool::stop(string vhost)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
std::vector<SrsDvrApiPlan*> plans;
|
||||
for (int i = 0; i < (int)dvrs.size(); i++) {
|
||||
SrsDvrApiPlan* plan = dvrs.at(i);
|
||||
if (!vhost.empty() && plan->req->vhost != vhost) {
|
||||
continue;
|
||||
}
|
||||
plans.push_back(plan);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)plans.size(); i++) {
|
||||
SrsDvrApiPlan* plan = plans.at(i);
|
||||
|
||||
if ((ret = plan->stop()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsApiDvrPool::rpc(SrsJsonAny* json)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (!json->is_object()) {
|
||||
ret = ERROR_HTTP_DVR_REQUEST;
|
||||
srs_error("dvr: rpc required object request. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsJsonObject* obj = json->to_object();
|
||||
|
||||
SrsJsonAny* prop = NULL;
|
||||
if ((prop = obj->ensure_property_string("vhost")) == NULL) {
|
||||
ret = ERROR_HTTP_DVR_REQUEST;
|
||||
srs_error("dvr: rpc required vhost request. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
std::string vhost = prop->to_str();
|
||||
|
||||
std::vector<SrsDvrApiPlan*> plans;
|
||||
for (int i = 0; i < (int)dvrs.size(); i++) {
|
||||
SrsDvrApiPlan* plan = dvrs.at(i);
|
||||
if (!vhost.empty() && plan->req->vhost != vhost) {
|
||||
continue;
|
||||
}
|
||||
plans.push_back(plan);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)plans.size(); i++) {
|
||||
SrsDvrApiPlan* plan = plans.at(i);
|
||||
|
||||
if ((ret = plan->rpc(obj)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsDvr::SrsDvr(SrsSource* s)
|
||||
{
|
||||
source = s;
|
||||
source = NULL;
|
||||
plan = NULL;
|
||||
}
|
||||
|
||||
|
@ -1645,14 +1108,20 @@ SrsDvr::~SrsDvr()
|
|||
srs_freep(plan);
|
||||
}
|
||||
|
||||
int SrsDvr::initialize(SrsRequest* r)
|
||||
int SrsDvr::initialize(SrsSource* s, SrsRequest* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
source = s;
|
||||
|
||||
srs_freep(plan);
|
||||
plan = SrsDvrPlan::create_plan(r->vhost);
|
||||
|
||||
if ((ret = plan->initialize(source, r)) != ERROR_SUCCESS) {
|
||||
if ((ret = plan->initialize(r)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = source->on_dvr_request_sh()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1675,6 +1144,7 @@ void SrsDvr::on_unpublish()
|
|||
plan->on_unpublish();
|
||||
}
|
||||
|
||||
// TODO: FIXME: source should use shared message instead.
|
||||
int SrsDvr::on_meta_data(SrsOnMetaDataPacket* m)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
|
|
@ -58,7 +58,6 @@ class SrsThread;
|
|||
class SrsFlvSegment : public ISrsReloadHandler
|
||||
{
|
||||
private:
|
||||
SrsSource* source;
|
||||
SrsRequest* req;
|
||||
SrsDvrPlan* plan;
|
||||
private:
|
||||
|
@ -121,7 +120,7 @@ public:
|
|||
/**
|
||||
* initialize the segment.
|
||||
*/
|
||||
virtual int initialize(SrsSource* s, SrsRequest* r);
|
||||
virtual int initialize(SrsRequest* r);
|
||||
/**
|
||||
* whether segment is overflow.
|
||||
*/
|
||||
|
@ -200,19 +199,6 @@ public:
|
|||
virtual int call();
|
||||
virtual std::string to_string();
|
||||
};
|
||||
class SrsDvrAsyncCallOnSegment : public ISrsDvrAsyncCall
|
||||
{
|
||||
private:
|
||||
std::string callback;
|
||||
std::string path;
|
||||
SrsRequest* req;
|
||||
public:
|
||||
SrsDvrAsyncCallOnSegment(SrsRequest* r, std::string c, std::string p);
|
||||
virtual ~SrsDvrAsyncCallOnSegment();
|
||||
public:
|
||||
virtual int call();
|
||||
virtual std::string to_string();
|
||||
};
|
||||
|
||||
/**
|
||||
* the async callback for dvr.
|
||||
|
@ -247,7 +233,6 @@ public:
|
|||
public:
|
||||
SrsRequest* req;
|
||||
protected:
|
||||
SrsSource* source;
|
||||
SrsFlvSegment* segment;
|
||||
SrsDvrAsyncCallThread* async;
|
||||
bool dvr_enabled;
|
||||
|
@ -255,7 +240,7 @@ public:
|
|||
SrsDvrPlan();
|
||||
virtual ~SrsDvrPlan();
|
||||
public:
|
||||
virtual int initialize(SrsSource* s, SrsRequest* r);
|
||||
virtual int initialize(SrsRequest* r);
|
||||
virtual int on_publish() = 0;
|
||||
virtual void on_unpublish() = 0;
|
||||
/**
|
||||
|
@ -272,7 +257,6 @@ public:
|
|||
virtual int on_video(SrsSharedPtrMessage* __video);
|
||||
protected:
|
||||
virtual int on_reap_segment();
|
||||
virtual int on_dvr_request_sh();
|
||||
virtual int on_video_keyframe();
|
||||
virtual int64_t filter_timestamp(int64_t timestamp);
|
||||
public:
|
||||
|
@ -292,48 +276,6 @@ public:
|
|||
virtual void on_unpublish();
|
||||
};
|
||||
|
||||
/**
|
||||
* api plan: reap flv by api.
|
||||
*/
|
||||
class SrsDvrApiPlan : public SrsDvrPlan
|
||||
{
|
||||
private:
|
||||
// cache the metadata and sequence header, for new segment maybe opened.
|
||||
SrsSharedPtrMessage* sh_audio;
|
||||
SrsSharedPtrMessage* sh_video;
|
||||
SrsSharedPtrMessage* metadata;
|
||||
private:
|
||||
std::string callback;
|
||||
bool autostart;
|
||||
bool started;
|
||||
private:
|
||||
// user action, reap_segment.
|
||||
std::string action;
|
||||
std::string path_template;
|
||||
public:
|
||||
SrsDvrApiPlan();
|
||||
virtual ~SrsDvrApiPlan();
|
||||
public:
|
||||
virtual int initialize(SrsSource* s, SrsRequest* r);
|
||||
virtual int on_publish();
|
||||
virtual void on_unpublish();
|
||||
virtual int on_meta_data(SrsSharedPtrMessage* __metadata);
|
||||
virtual int on_audio(SrsSharedPtrMessage* __audio);
|
||||
virtual int on_video(SrsSharedPtrMessage* __video);
|
||||
public:
|
||||
virtual int set_path_tmpl(std::string path_tmpl);
|
||||
virtual int set_callback(std::string value);
|
||||
virtual int set_wait_keyframe(bool wait_keyframe);
|
||||
virtual int start();
|
||||
virtual int dumps(std::stringstream& ss);
|
||||
virtual int stop();
|
||||
virtual int rpc(SrsJsonObject* obj);
|
||||
protected:
|
||||
virtual int on_reap_segment();
|
||||
private:
|
||||
virtual int check_user_actions(SrsSharedPtrMessage* msg);
|
||||
};
|
||||
|
||||
/**
|
||||
* always append to flv file, never reap it.
|
||||
*/
|
||||
|
@ -368,7 +310,7 @@ public:
|
|||
SrsDvrSegmentPlan();
|
||||
virtual ~SrsDvrSegmentPlan();
|
||||
public:
|
||||
virtual int initialize(SrsSource* source, SrsRequest* req);
|
||||
virtual int initialize(SrsRequest* req);
|
||||
virtual int on_publish();
|
||||
virtual void on_unpublish();
|
||||
virtual int on_meta_data(SrsSharedPtrMessage* __metadata);
|
||||
|
@ -378,28 +320,6 @@ private:
|
|||
virtual int update_duration(SrsSharedPtrMessage* msg);
|
||||
};
|
||||
|
||||
/**
|
||||
* the api dvr pool.
|
||||
*/
|
||||
class SrsApiDvrPool
|
||||
{
|
||||
private:
|
||||
std::vector<SrsDvrApiPlan*> dvrs;
|
||||
static SrsApiDvrPool* _instance;
|
||||
private:
|
||||
SrsApiDvrPool();
|
||||
public:
|
||||
static SrsApiDvrPool* instance();
|
||||
virtual ~SrsApiDvrPool();
|
||||
public:
|
||||
virtual int add_dvr(SrsDvrApiPlan* dvr);
|
||||
public:
|
||||
virtual int dumps(std::string vhost, std::stringstream& ss);
|
||||
virtual int create(SrsJsonAny* json);
|
||||
virtual int stop(std::string vhost);
|
||||
virtual int rpc(SrsJsonAny* json);
|
||||
};
|
||||
|
||||
/**
|
||||
* dvr(digital video recorder) to record RTMP stream to flv file.
|
||||
* TODO: FIXME: add utest for it.
|
||||
|
@ -411,7 +331,7 @@ private:
|
|||
private:
|
||||
SrsDvrPlan* plan;
|
||||
public:
|
||||
SrsDvr(SrsSource* s);
|
||||
SrsDvr();
|
||||
virtual ~SrsDvr();
|
||||
public:
|
||||
/**
|
||||
|
@ -419,7 +339,7 @@ public:
|
|||
* when system initialize(encoder publish at first time, or reload),
|
||||
* initialize the dvr will reinitialize the plan, the whole dvr framework.
|
||||
*/
|
||||
virtual int initialize(SrsRequest* r);
|
||||
virtual int initialize(SrsSource* s, SrsRequest* r);
|
||||
/**
|
||||
* publish stream event,
|
||||
* when encoder start to publish RTMP stream.
|
||||
|
|
|
@ -432,8 +432,8 @@ int SrsFFMPEG::start()
|
|||
// memory leak in child process, it's ok.
|
||||
char** charpv_params = new char*[params.size() + 1];
|
||||
for (int i = 0; i < (int)params.size(); i++) {
|
||||
std::string p = params[i];
|
||||
charpv_params[i] = (char*)p.c_str();
|
||||
std::string& p = params[i];
|
||||
charpv_params[i] = (char*)p.data();
|
||||
}
|
||||
// EOF: NULL
|
||||
charpv_params[params.size()] = NULL;
|
||||
|
|
|
@ -35,6 +35,7 @@ using namespace std;
|
|||
#include <srs_app_json.hpp>
|
||||
#include <srs_app_http.hpp>
|
||||
#include <srs_app_utility.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
|
||||
SrsHttpHeartbeat::SrsHttpHeartbeat()
|
||||
{
|
||||
|
@ -73,21 +74,31 @@ void SrsHttpHeartbeat::heartbeat()
|
|||
srs_api_dump_summaries(ss);
|
||||
}
|
||||
ss << __SRS_JOBJECT_END;
|
||||
std::string data = ss.str();
|
||||
std::string res;
|
||||
int status_code;
|
||||
|
||||
std::string req = ss.str();
|
||||
|
||||
SrsHttpClient http;
|
||||
if ((ret = http.post(&uri, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
if ((ret = http.initialize(uri.get_host(), uri.get_port())) != ERROR_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
SrsHttpMessage* msg = NULL;
|
||||
if ((ret = http.post(uri.get_path(), req, &msg)) != ERROR_SUCCESS) {
|
||||
srs_info("http post hartbeart uri failed. "
|
||||
"url=%s, request=%s, response=%s, ret=%d",
|
||||
url.c_str(), data.c_str(), res.c_str(), ret);
|
||||
url.c_str(), req.c_str(), res.c_str(), ret);
|
||||
return;
|
||||
}
|
||||
SrsAutoFree(SrsHttpMessage, msg);
|
||||
|
||||
std::string res;
|
||||
if ((ret = msg->body_read_all(res)) != ERROR_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
srs_info("http hook hartbeart success. "
|
||||
"url=%s, request=%s, status_code=%d, response=%s, ret=%d",
|
||||
url.c_str(), data.c_str(), status_code, res.c_str(), ret);
|
||||
url.c_str(), req.c_str(), status_code, res.c_str(), ret);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -163,10 +163,10 @@ void SrsHlsSegment::update_duration(int64_t current_frame_dts)
|
|||
return;
|
||||
}
|
||||
|
||||
SrsHlsMuxer::SrsHlsMuxer(ISrsHlsHandler* h)
|
||||
SrsHlsMuxer::SrsHlsMuxer()
|
||||
{
|
||||
req = NULL;
|
||||
handler = h;
|
||||
handler = NULL;
|
||||
hls_fragment = hls_window = 0;
|
||||
target_duration = 0;
|
||||
_sequence_no = 0;
|
||||
|
@ -189,6 +189,15 @@ SrsHlsMuxer::~SrsHlsMuxer()
|
|||
srs_freep(req);
|
||||
}
|
||||
|
||||
int SrsHlsMuxer::initialize(ISrsHlsHandler* h)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
handler = h;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsHlsMuxer::sequence_no()
|
||||
{
|
||||
return _sequence_no;
|
||||
|
@ -811,10 +820,10 @@ int SrsHlsCache::reap_segment(string log_desc, SrsHlsMuxer* muxer, int64_t segme
|
|||
return ret;
|
||||
}
|
||||
|
||||
SrsHls::SrsHls(SrsSource* s, ISrsHlsHandler* h)
|
||||
SrsHls::SrsHls()
|
||||
{
|
||||
source = s;
|
||||
handler = h;
|
||||
source = NULL;
|
||||
handler = NULL;
|
||||
|
||||
hls_enabled = false;
|
||||
|
||||
|
@ -822,7 +831,7 @@ SrsHls::SrsHls(SrsSource* s, ISrsHlsHandler* h)
|
|||
sample = new SrsCodecSample();
|
||||
jitter = new SrsRtmpJitter();
|
||||
|
||||
muxer = new SrsHlsMuxer(h);
|
||||
muxer = new SrsHlsMuxer();
|
||||
hls_cache = new SrsHlsCache();
|
||||
|
||||
pprint = SrsPithyPrint::create_hls();
|
||||
|
@ -841,6 +850,20 @@ SrsHls::~SrsHls()
|
|||
srs_freep(pprint);
|
||||
}
|
||||
|
||||
int SrsHls::initialize(SrsSource* s, ISrsHlsHandler* h)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
source = s;
|
||||
handler = h;
|
||||
|
||||
if ((ret = muxer->initialize(h)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsHls::on_publish(SrsRequest* req)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
|
|
@ -195,11 +195,15 @@ private:
|
|||
*/
|
||||
SrsCodecAudio acodec;
|
||||
public:
|
||||
SrsHlsMuxer(ISrsHlsHandler* h);
|
||||
SrsHlsMuxer();
|
||||
virtual ~SrsHlsMuxer();
|
||||
public:
|
||||
virtual int sequence_no();
|
||||
public:
|
||||
/**
|
||||
* initialize the hls muxer.
|
||||
*/
|
||||
virtual int initialize(ISrsHlsHandler* h);
|
||||
/**
|
||||
* when publish, update the config for muxer.
|
||||
*/
|
||||
|
@ -325,9 +329,13 @@ private:
|
|||
*/
|
||||
int64_t stream_dts;
|
||||
public:
|
||||
SrsHls(SrsSource* s, ISrsHlsHandler* h);
|
||||
SrsHls();
|
||||
virtual ~SrsHls();
|
||||
public:
|
||||
/**
|
||||
* initialize the hls by handler and source.
|
||||
*/
|
||||
virtual int initialize(SrsSource* s, ISrsHlsHandler* h);
|
||||
/**
|
||||
* publish stream event, continue to write the m3u8,
|
||||
* for the muxer object not destroyed.
|
||||
|
|
|
@ -39,11 +39,10 @@ using namespace std;
|
|||
#include <srs_rtmp_buffer.hpp>
|
||||
#include <srs_kernel_file.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
#include <srs_rtmp_buffer.hpp>
|
||||
|
||||
#define SRS_DEFAULT_HTTP_PORT 80
|
||||
|
||||
#define SRS_HTTP_HEADER_BUFFER 1024
|
||||
|
||||
// for http parser macros
|
||||
#define SRS_CONSTS_HTTP_OPTIONS HTTP_OPTIONS
|
||||
#define SRS_CONSTS_HTTP_GET HTTP_GET
|
||||
|
@ -53,7 +52,7 @@ using namespace std;
|
|||
|
||||
#define SRS_HTTP_DEFAULT_PAGE "index.html"
|
||||
|
||||
int srs_go_http_response_json(ISrsGoHttpResponseWriter* w, string data)
|
||||
int srs_go_http_response_json(ISrsHttpResponseWriter* w, string data)
|
||||
{
|
||||
w->header()->set_content_length(data.length());
|
||||
w->header()->set_content_type("application/json");
|
||||
|
@ -147,7 +146,7 @@ string srs_go_http_detect(char* data, int size)
|
|||
|
||||
// Error replies to the request with the specified error message and HTTP code.
|
||||
// The error message should be plain text.
|
||||
int srs_go_http_error(ISrsGoHttpResponseWriter* w, int code, string error)
|
||||
int srs_go_http_error(ISrsHttpResponseWriter* w, int code, string error)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -159,20 +158,20 @@ int srs_go_http_error(ISrsGoHttpResponseWriter* w, int code, string error)
|
|||
return ret;
|
||||
}
|
||||
|
||||
SrsGoHttpHeader::SrsGoHttpHeader()
|
||||
SrsHttpHeader::SrsHttpHeader()
|
||||
{
|
||||
}
|
||||
|
||||
SrsGoHttpHeader::~SrsGoHttpHeader()
|
||||
SrsHttpHeader::~SrsHttpHeader()
|
||||
{
|
||||
}
|
||||
|
||||
void SrsGoHttpHeader::set(string key, string value)
|
||||
void SrsHttpHeader::set(string key, string value)
|
||||
{
|
||||
headers[key] = value;
|
||||
}
|
||||
|
||||
string SrsGoHttpHeader::get(string key)
|
||||
string SrsHttpHeader::get(string key)
|
||||
{
|
||||
std::string v;
|
||||
|
||||
|
@ -183,7 +182,7 @@ string SrsGoHttpHeader::get(string key)
|
|||
return v;
|
||||
}
|
||||
|
||||
int64_t SrsGoHttpHeader::content_length()
|
||||
int64_t SrsHttpHeader::content_length()
|
||||
{
|
||||
std::string cl = get("Content-Length");
|
||||
|
||||
|
@ -194,24 +193,24 @@ int64_t SrsGoHttpHeader::content_length()
|
|||
return (int64_t)::atof(cl.c_str());
|
||||
}
|
||||
|
||||
void SrsGoHttpHeader::set_content_length(int64_t size)
|
||||
void SrsHttpHeader::set_content_length(int64_t size)
|
||||
{
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "%"PRId64, size);
|
||||
set("Content-Length", buf);
|
||||
}
|
||||
|
||||
string SrsGoHttpHeader::content_type()
|
||||
string SrsHttpHeader::content_type()
|
||||
{
|
||||
return get("Content-Type");
|
||||
}
|
||||
|
||||
void SrsGoHttpHeader::set_content_type(string ct)
|
||||
void SrsHttpHeader::set_content_type(string ct)
|
||||
{
|
||||
set("Content-Type", ct);
|
||||
}
|
||||
|
||||
void SrsGoHttpHeader::write(stringstream& ss)
|
||||
void SrsHttpHeader::write(stringstream& ss)
|
||||
{
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
for (it = headers.begin(); it != headers.end(); ++it) {
|
||||
|
@ -219,64 +218,72 @@ void SrsGoHttpHeader::write(stringstream& ss)
|
|||
}
|
||||
}
|
||||
|
||||
ISrsGoHttpResponseWriter::ISrsGoHttpResponseWriter()
|
||||
ISrsHttpResponseWriter::ISrsHttpResponseWriter()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsGoHttpResponseWriter::~ISrsGoHttpResponseWriter()
|
||||
ISrsHttpResponseWriter::~ISrsHttpResponseWriter()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsGoHttpHandler::ISrsGoHttpHandler()
|
||||
ISrsHttpResponseReader::ISrsHttpResponseReader()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsHttpResponseReader::~ISrsHttpResponseReader()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsHttpHandler::ISrsHttpHandler()
|
||||
{
|
||||
entry = NULL;
|
||||
}
|
||||
|
||||
ISrsGoHttpHandler::~ISrsGoHttpHandler()
|
||||
ISrsHttpHandler::~ISrsHttpHandler()
|
||||
{
|
||||
}
|
||||
|
||||
SrsGoHttpRedirectHandler::SrsGoHttpRedirectHandler(string u, int c)
|
||||
SrsHttpRedirectHandler::SrsHttpRedirectHandler(string u, int c)
|
||||
{
|
||||
url = u;
|
||||
code = c;
|
||||
}
|
||||
|
||||
SrsGoHttpRedirectHandler::~SrsGoHttpRedirectHandler()
|
||||
SrsHttpRedirectHandler::~SrsHttpRedirectHandler()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsGoHttpRedirectHandler::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsHttpRedirectHandler::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
// TODO: FIXME: implements it.
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsGoHttpNotFoundHandler::SrsGoHttpNotFoundHandler()
|
||||
SrsHttpNotFoundHandler::SrsHttpNotFoundHandler()
|
||||
{
|
||||
}
|
||||
|
||||
SrsGoHttpNotFoundHandler::~SrsGoHttpNotFoundHandler()
|
||||
SrsHttpNotFoundHandler::~SrsHttpNotFoundHandler()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsGoHttpNotFoundHandler::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsHttpNotFoundHandler::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
return srs_go_http_error(w,
|
||||
SRS_CONSTS_HTTP_NotFound, SRS_CONSTS_HTTP_NotFound_str);
|
||||
}
|
||||
|
||||
SrsGoHttpFileServer::SrsGoHttpFileServer(string root_dir)
|
||||
SrsHttpFileServer::SrsHttpFileServer(string root_dir)
|
||||
{
|
||||
dir = root_dir;
|
||||
}
|
||||
|
||||
SrsGoHttpFileServer::~SrsGoHttpFileServer()
|
||||
SrsHttpFileServer::~SrsHttpFileServer()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsGoHttpFileServer::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsHttpFileServer::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
string upath = r->path();
|
||||
|
||||
|
@ -300,7 +307,7 @@ int SrsGoHttpFileServer::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage*
|
|||
if (!srs_path_exists(fullpath)) {
|
||||
srs_warn("http miss file=%s, pattern=%s, upath=%s",
|
||||
fullpath.c_str(), entry->pattern.c_str(), upath.c_str());
|
||||
return SrsGoHttpNotFoundHandler().serve_http(w, r);
|
||||
return SrsHttpNotFoundHandler().serve_http(w, r);
|
||||
}
|
||||
srs_trace("http match file=%s, pattern=%s, upath=%s",
|
||||
fullpath.c_str(), entry->pattern.c_str(), upath.c_str());
|
||||
|
@ -317,7 +324,7 @@ int SrsGoHttpFileServer::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage*
|
|||
return serve_file(w, r, fullpath);
|
||||
}
|
||||
|
||||
int SrsGoHttpFileServer::serve_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath)
|
||||
int SrsHttpFileServer::serve_file(ISrsHttpResponseWriter* w, SrsHttpMessage* r, string fullpath)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -391,7 +398,7 @@ int SrsGoHttpFileServer::serve_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage*
|
|||
return w->final_request();
|
||||
}
|
||||
|
||||
int SrsGoHttpFileServer::serve_flv_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath)
|
||||
int SrsHttpFileServer::serve_flv_file(ISrsHttpResponseWriter* w, SrsHttpMessage* r, string fullpath)
|
||||
{
|
||||
std::string start = r->query_get("start");
|
||||
if (start.empty()) {
|
||||
|
@ -406,7 +413,7 @@ int SrsGoHttpFileServer::serve_flv_file(ISrsGoHttpResponseWriter* w, SrsHttpMess
|
|||
return serve_flv_stream(w, r, fullpath, offset);
|
||||
}
|
||||
|
||||
int SrsGoHttpFileServer::serve_mp4_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath)
|
||||
int SrsHttpFileServer::serve_mp4_file(ISrsHttpResponseWriter* w, SrsHttpMessage* r, string fullpath)
|
||||
{
|
||||
// for flash to request mp4 range in query string.
|
||||
// for example, http://digitalprimates.net/dash/DashTest.html?url=http://dashdemo.edgesuite.net/digitalprimates/nexus/oops-20120802-manifest.mpd
|
||||
|
@ -443,17 +450,17 @@ int SrsGoHttpFileServer::serve_mp4_file(ISrsGoHttpResponseWriter* w, SrsHttpMess
|
|||
return serve_mp4_stream(w, r, fullpath, start, end);
|
||||
}
|
||||
|
||||
int SrsGoHttpFileServer::serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int offset)
|
||||
int SrsHttpFileServer::serve_flv_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int offset)
|
||||
{
|
||||
return serve_file(w, r, fullpath);
|
||||
}
|
||||
|
||||
int SrsGoHttpFileServer::serve_mp4_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int start, int end)
|
||||
int SrsHttpFileServer::serve_mp4_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int start, int end)
|
||||
{
|
||||
return serve_file(w, r, fullpath);
|
||||
}
|
||||
|
||||
int SrsGoHttpFileServer::copy(ISrsGoHttpResponseWriter* w, SrsFileReader* fs, SrsHttpMessage* r, int size)
|
||||
int SrsHttpFileServer::copy(ISrsHttpResponseWriter* w, SrsFileReader* fs, SrsHttpMessage* r, int size)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -476,27 +483,27 @@ int SrsGoHttpFileServer::copy(ISrsGoHttpResponseWriter* w, SrsFileReader* fs, Sr
|
|||
return ret;
|
||||
}
|
||||
|
||||
SrsGoHttpMuxEntry::SrsGoHttpMuxEntry()
|
||||
SrsHttpMuxEntry::SrsHttpMuxEntry()
|
||||
{
|
||||
enabled = true;
|
||||
explicit_match = false;
|
||||
handler = NULL;
|
||||
}
|
||||
|
||||
SrsGoHttpMuxEntry::~SrsGoHttpMuxEntry()
|
||||
SrsHttpMuxEntry::~SrsHttpMuxEntry()
|
||||
{
|
||||
srs_freep(handler);
|
||||
}
|
||||
|
||||
SrsGoHttpServeMux::SrsGoHttpServeMux()
|
||||
SrsHttpServeMux::SrsHttpServeMux()
|
||||
{
|
||||
}
|
||||
|
||||
SrsGoHttpServeMux::~SrsGoHttpServeMux()
|
||||
SrsHttpServeMux::~SrsHttpServeMux()
|
||||
{
|
||||
std::map<std::string, SrsGoHttpMuxEntry*>::iterator it;
|
||||
std::map<std::string, SrsHttpMuxEntry*>::iterator it;
|
||||
for (it = entries.begin(); it != entries.end(); ++it) {
|
||||
SrsGoHttpMuxEntry* entry = it->second;
|
||||
SrsHttpMuxEntry* entry = it->second;
|
||||
srs_freep(entry);
|
||||
}
|
||||
entries.clear();
|
||||
|
@ -504,14 +511,14 @@ SrsGoHttpServeMux::~SrsGoHttpServeMux()
|
|||
vhosts.clear();
|
||||
}
|
||||
|
||||
int SrsGoHttpServeMux::initialize()
|
||||
int SrsHttpServeMux::initialize()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
// TODO: FIXME: implements it.
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsGoHttpServeMux::handle(std::string pattern, ISrsGoHttpHandler* handler)
|
||||
int SrsHttpServeMux::handle(std::string pattern, ISrsHttpHandler* handler)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -524,7 +531,7 @@ int SrsGoHttpServeMux::handle(std::string pattern, ISrsGoHttpHandler* handler)
|
|||
}
|
||||
|
||||
if (entries.find(pattern) != entries.end()) {
|
||||
SrsGoHttpMuxEntry* exists = entries[pattern];
|
||||
SrsHttpMuxEntry* exists = entries[pattern];
|
||||
if (exists->explicit_match) {
|
||||
ret = ERROR_HTTP_PATTERN_DUPLICATED;
|
||||
srs_error("http: multiple registrations for %s. ret=%d", pattern.c_str(), ret);
|
||||
|
@ -541,14 +548,14 @@ int SrsGoHttpServeMux::handle(std::string pattern, ISrsGoHttpHandler* handler)
|
|||
}
|
||||
|
||||
if (true) {
|
||||
SrsGoHttpMuxEntry* entry = new SrsGoHttpMuxEntry();
|
||||
SrsHttpMuxEntry* entry = new SrsHttpMuxEntry();
|
||||
entry->explicit_match = true;
|
||||
entry->handler = handler;
|
||||
entry->pattern = pattern;
|
||||
entry->handler->entry = entry;
|
||||
|
||||
if (entries.find(pattern) != entries.end()) {
|
||||
SrsGoHttpMuxEntry* exists = entries[pattern];
|
||||
SrsHttpMuxEntry* exists = entries[pattern];
|
||||
srs_freep(exists);
|
||||
}
|
||||
entries[pattern] = entry;
|
||||
|
@ -559,11 +566,11 @@ int SrsGoHttpServeMux::handle(std::string pattern, ISrsGoHttpHandler* handler)
|
|||
// It can be overridden by an explicit registration.
|
||||
if (pattern != "/" && !pattern.empty() && pattern.at(pattern.length() - 1) == '/') {
|
||||
std::string rpattern = pattern.substr(0, pattern.length() - 1);
|
||||
SrsGoHttpMuxEntry* entry = NULL;
|
||||
SrsHttpMuxEntry* entry = NULL;
|
||||
|
||||
// free the exists not explicit entry
|
||||
if (entries.find(rpattern) != entries.end()) {
|
||||
SrsGoHttpMuxEntry* exists = entries[rpattern];
|
||||
SrsHttpMuxEntry* exists = entries[rpattern];
|
||||
if (!exists->explicit_match) {
|
||||
entry = exists;
|
||||
}
|
||||
|
@ -573,9 +580,9 @@ int SrsGoHttpServeMux::handle(std::string pattern, ISrsGoHttpHandler* handler)
|
|||
if (!entry || entry->explicit_match) {
|
||||
srs_freep(entry);
|
||||
|
||||
entry = new SrsGoHttpMuxEntry();
|
||||
entry = new SrsHttpMuxEntry();
|
||||
entry->explicit_match = false;
|
||||
entry->handler = new SrsGoHttpRedirectHandler(pattern, SRS_CONSTS_HTTP_MovedPermanently);
|
||||
entry->handler = new SrsHttpRedirectHandler(pattern, SRS_CONSTS_HTTP_MovedPermanently);
|
||||
entry->pattern = pattern;
|
||||
entry->handler->entry = entry;
|
||||
|
||||
|
@ -586,11 +593,11 @@ int SrsGoHttpServeMux::handle(std::string pattern, ISrsGoHttpHandler* handler)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsGoHttpServeMux::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsHttpServeMux::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
ISrsGoHttpHandler* h = NULL;
|
||||
ISrsHttpHandler* h = NULL;
|
||||
if ((ret = find_handler(r, &h)) != ERROR_SUCCESS) {
|
||||
srs_error("find handler failed. ret=%d", ret);
|
||||
return ret;
|
||||
|
@ -607,7 +614,7 @@ int SrsGoHttpServeMux::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsGoHttpServeMux::find_handler(SrsHttpMessage* r, ISrsGoHttpHandler** ph)
|
||||
int SrsHttpServeMux::find_handler(SrsHttpMessage* r, ISrsHttpHandler** ph)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -624,13 +631,13 @@ int SrsGoHttpServeMux::find_handler(SrsHttpMessage* r, ISrsGoHttpHandler** ph)
|
|||
}
|
||||
|
||||
if (*ph == NULL) {
|
||||
*ph = new SrsGoHttpNotFoundHandler();
|
||||
*ph = new SrsHttpNotFoundHandler();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsGoHttpServeMux::match(SrsHttpMessage* r, ISrsGoHttpHandler** ph)
|
||||
int SrsHttpServeMux::match(SrsHttpMessage* r, ISrsHttpHandler** ph)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -642,12 +649,12 @@ int SrsGoHttpServeMux::match(SrsHttpMessage* r, ISrsGoHttpHandler** ph)
|
|||
}
|
||||
|
||||
int nb_matched = 0;
|
||||
ISrsGoHttpHandler* h = NULL;
|
||||
ISrsHttpHandler* h = NULL;
|
||||
|
||||
std::map<std::string, SrsGoHttpMuxEntry*>::iterator it;
|
||||
std::map<std::string, SrsHttpMuxEntry*>::iterator it;
|
||||
for (it = entries.begin(); it != entries.end(); ++it) {
|
||||
std::string pattern = it->first;
|
||||
SrsGoHttpMuxEntry* entry = it->second;
|
||||
SrsHttpMuxEntry* entry = it->second;
|
||||
|
||||
if (!entry->enabled) {
|
||||
continue;
|
||||
|
@ -668,7 +675,7 @@ int SrsGoHttpServeMux::match(SrsHttpMessage* r, ISrsGoHttpHandler** ph)
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool SrsGoHttpServeMux::path_match(string pattern, string path)
|
||||
bool SrsHttpServeMux::path_match(string pattern, string path)
|
||||
{
|
||||
if (pattern.empty()) {
|
||||
return false;
|
||||
|
@ -692,10 +699,10 @@ bool SrsGoHttpServeMux::path_match(string pattern, string path)
|
|||
return false;
|
||||
}
|
||||
|
||||
SrsGoHttpResponseWriter::SrsGoHttpResponseWriter(SrsStSocket* io)
|
||||
SrsHttpResponseWriter::SrsHttpResponseWriter(SrsStSocket* io)
|
||||
{
|
||||
skt = io;
|
||||
hdr = new SrsGoHttpHeader();
|
||||
hdr = new SrsHttpHeader();
|
||||
header_wrote = false;
|
||||
status = SRS_CONSTS_HTTP_OK;
|
||||
content_length = -1;
|
||||
|
@ -703,12 +710,12 @@ SrsGoHttpResponseWriter::SrsGoHttpResponseWriter(SrsStSocket* io)
|
|||
header_sent = false;
|
||||
}
|
||||
|
||||
SrsGoHttpResponseWriter::~SrsGoHttpResponseWriter()
|
||||
SrsHttpResponseWriter::~SrsHttpResponseWriter()
|
||||
{
|
||||
srs_freep(hdr);
|
||||
}
|
||||
|
||||
int SrsGoHttpResponseWriter::final_request()
|
||||
int SrsHttpResponseWriter::final_request()
|
||||
{
|
||||
// complete the chunked encoding.
|
||||
if (content_length == -1) {
|
||||
|
@ -722,12 +729,12 @@ int SrsGoHttpResponseWriter::final_request()
|
|||
return write(NULL, 0);
|
||||
}
|
||||
|
||||
SrsGoHttpHeader* SrsGoHttpResponseWriter::header()
|
||||
SrsHttpHeader* SrsHttpResponseWriter::header()
|
||||
{
|
||||
return hdr;
|
||||
}
|
||||
|
||||
int SrsGoHttpResponseWriter::write(char* data, int size)
|
||||
int SrsHttpResponseWriter::write(char* data, int size)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -774,7 +781,7 @@ int SrsGoHttpResponseWriter::write(char* data, int size)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void SrsGoHttpResponseWriter::write_header(int code)
|
||||
void SrsHttpResponseWriter::write_header(int code)
|
||||
{
|
||||
if (header_wrote) {
|
||||
srs_warn("http: multiple write_header calls, code=%d", code);
|
||||
|
@ -788,7 +795,7 @@ void SrsGoHttpResponseWriter::write_header(int code)
|
|||
content_length = hdr->content_length();
|
||||
}
|
||||
|
||||
int SrsGoHttpResponseWriter::send_header(char* data, int size)
|
||||
int SrsHttpResponseWriter::send_header(char* data, int size)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -833,11 +840,166 @@ int SrsGoHttpResponseWriter::send_header(char* data, int size)
|
|||
return skt->write((void*)buf.c_str(), buf.length(), NULL);
|
||||
}
|
||||
|
||||
SrsHttpMessage::SrsHttpMessage()
|
||||
SrsHttpResponseReader::SrsHttpResponseReader(SrsHttpMessage* msg, SrsStSocket* io)
|
||||
{
|
||||
_body = new SrsSimpleBuffer();
|
||||
_state = SrsHttpParseStateInit;
|
||||
skt = io;
|
||||
owner = msg;
|
||||
is_eof = false;
|
||||
nb_read = 0;
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
SrsHttpResponseReader::~SrsHttpResponseReader()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsHttpResponseReader::initialize(SrsFastBuffer* body)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
buffer = body;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool SrsHttpResponseReader::eof()
|
||||
{
|
||||
return is_eof;
|
||||
}
|
||||
|
||||
int SrsHttpResponseReader::read(std::string& data)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (is_eof) {
|
||||
ret = ERROR_HTTP_RESPONSE_EOF;
|
||||
srs_error("http: response EOF. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// chunked encoding.
|
||||
if (owner->is_chunked()) {
|
||||
return read_chunked(data);
|
||||
}
|
||||
|
||||
// read by specified content-length
|
||||
int max = (int)owner->content_length() - nb_read;
|
||||
if (max <= 0) {
|
||||
is_eof = true;
|
||||
return ret;
|
||||
}
|
||||
return read_specified(max, data);
|
||||
}
|
||||
|
||||
int SrsHttpResponseReader::read_chunked(std::string& data)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// parse the chunk length first.
|
||||
char* at = NULL;
|
||||
int length = 0;
|
||||
while (!at) {
|
||||
// find the CRLF of chunk header end.
|
||||
char* start = buffer->bytes();
|
||||
char* end = start + buffer->size();
|
||||
for (char* p = start; p < end - 1; p++) {
|
||||
if (p[0] == __SRS_HTTP_CR && p[1] == __SRS_HTTP_LF) {
|
||||
// invalid chunk, ignore.
|
||||
if (p == start) {
|
||||
ret = ERROR_HTTP_INVALID_CHUNK_HEADER;
|
||||
srs_error("chunk header start with CRLF. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
length = p - start + 2;
|
||||
at = buffer->read_slice(length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// got at, ok.
|
||||
if (at) {
|
||||
break;
|
||||
}
|
||||
|
||||
// when empty, only grow 1bytes, but the buffer will cache more.
|
||||
if ((ret = buffer->grow(skt, buffer->size() + 1)) != ERROR_SUCCESS) {
|
||||
if (!srs_is_client_gracefully_close(ret)) {
|
||||
srs_error("read body from server failed. ret=%d", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
srs_assert(length >= 3);
|
||||
|
||||
// it's ok to set the pos and pos+1 to NULL.
|
||||
at[length - 1] = NULL;
|
||||
at[length - 2] = NULL;
|
||||
|
||||
// size is the bytes size, excludes the chunk header and end CRLF.
|
||||
int ilength = ::strtol(at, NULL, 16);
|
||||
if (ilength < 0) {
|
||||
ret = ERROR_HTTP_INVALID_CHUNK_HEADER;
|
||||
srs_error("chunk header negative, length=%d. ret=%d", ilength, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// when empty, only grow 1bytes, but the buffer will cache more.
|
||||
if ((ret = buffer->grow(skt, ilength + 2)) != ERROR_SUCCESS) {
|
||||
if (!srs_is_client_gracefully_close(ret)) {
|
||||
srs_error("read body from server failed. ret=%d", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
srs_info("http: read %d chunk", ilength);
|
||||
|
||||
// read payload when length specifies some payload.
|
||||
if (ilength <= 0) {
|
||||
is_eof = true;
|
||||
} else {
|
||||
srs_assert(ilength);
|
||||
data.append(buffer->read_slice(ilength), ilength);
|
||||
nb_read += ilength;
|
||||
}
|
||||
|
||||
// the CRLF of chunk payload end.
|
||||
buffer->read_slice(2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsHttpResponseReader::read_specified(int max, std::string& data)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (buffer->size() <= 0) {
|
||||
// when empty, only grow 1bytes, but the buffer will cache more.
|
||||
if ((ret = buffer->grow(skt, 1)) != ERROR_SUCCESS) {
|
||||
if (!srs_is_client_gracefully_close(ret)) {
|
||||
srs_error("read body from server failed. ret=%d", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
int nb_bytes = srs_min(max, buffer->size());
|
||||
|
||||
srs_assert(nb_bytes);
|
||||
data.append(buffer->read_slice(nb_bytes), nb_bytes);
|
||||
nb_read += nb_bytes;
|
||||
|
||||
// when read completed, eof.
|
||||
if (nb_read >= (int)owner->content_length()) {
|
||||
is_eof = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsHttpMessage::SrsHttpMessage(SrsStSocket* io)
|
||||
{
|
||||
chunked = false;
|
||||
_uri = new SrsHttpUri();
|
||||
_body = new SrsHttpResponseReader(this, io);
|
||||
_http_ts_send_buffer = new char[__SRS_HTTP_TS_SEND_BUFFER_SIZE];
|
||||
}
|
||||
|
||||
|
@ -848,10 +1010,24 @@ SrsHttpMessage::~SrsHttpMessage()
|
|||
srs_freep(_http_ts_send_buffer);
|
||||
}
|
||||
|
||||
int SrsHttpMessage::initialize()
|
||||
int SrsHttpMessage::update(string url, http_parser* header, SrsFastBuffer* body, vector<SrsHttpHeaderField>& headers)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
_url = url;
|
||||
_header = *header;
|
||||
_headers = headers;
|
||||
|
||||
// whether chunked.
|
||||
std::string transfer_encoding = get_request_header("Transfer-Encoding");
|
||||
chunked = (transfer_encoding == "chunked");
|
||||
|
||||
// set the buffer.
|
||||
if ((ret = _body->initialize(body)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// parse uri from url.
|
||||
std::string host = get_request_header("Host");
|
||||
|
||||
// donot parse the empty host for uri,
|
||||
|
@ -898,18 +1074,6 @@ char* SrsHttpMessage::http_ts_send_buffer()
|
|||
return _http_ts_send_buffer;
|
||||
}
|
||||
|
||||
void SrsHttpMessage::reset()
|
||||
{
|
||||
_state = SrsHttpParseStateInit;
|
||||
_body->erase(_body->length());
|
||||
_url = "";
|
||||
}
|
||||
|
||||
bool SrsHttpMessage::is_complete()
|
||||
{
|
||||
return _state == SrsHttpParseStateComplete;
|
||||
}
|
||||
|
||||
u_int8_t SrsHttpMessage::method()
|
||||
{
|
||||
return (u_int8_t)_header.method;
|
||||
|
@ -966,6 +1130,11 @@ bool SrsHttpMessage::is_http_options()
|
|||
return _header.method == SRS_CONSTS_HTTP_OPTIONS;
|
||||
}
|
||||
|
||||
bool SrsHttpMessage::is_chunked()
|
||||
{
|
||||
return chunked;
|
||||
}
|
||||
|
||||
string SrsHttpMessage::uri()
|
||||
{
|
||||
std::string uri = _uri->get_schema();
|
||||
|
@ -993,25 +1162,23 @@ string SrsHttpMessage::path()
|
|||
return _uri->get_path();
|
||||
}
|
||||
|
||||
string SrsHttpMessage::body()
|
||||
int SrsHttpMessage::body_read_all(string& body)
|
||||
{
|
||||
std::string b;
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (_body && _body->length() > 0) {
|
||||
b.append(_body->bytes(), _body->length());
|
||||
// whatever, read util EOF.
|
||||
while (!_body->eof()) {
|
||||
if ((ret = _body->read(body)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return b;
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* SrsHttpMessage::body_raw()
|
||||
ISrsHttpResponseReader* SrsHttpMessage::body_reader()
|
||||
{
|
||||
return _body? _body->bytes() : NULL;
|
||||
}
|
||||
|
||||
int64_t SrsHttpMessage::body_size()
|
||||
{
|
||||
return (int64_t)_body->length();
|
||||
return _body;
|
||||
}
|
||||
|
||||
int64_t SrsHttpMessage::content_length()
|
||||
|
@ -1019,26 +1186,6 @@ int64_t SrsHttpMessage::content_length()
|
|||
return _header.content_length;
|
||||
}
|
||||
|
||||
void SrsHttpMessage::set_url(string url)
|
||||
{
|
||||
_url = url;
|
||||
}
|
||||
|
||||
void SrsHttpMessage::set_state(SrsHttpParseState state)
|
||||
{
|
||||
_state = state;
|
||||
}
|
||||
|
||||
void SrsHttpMessage::set_header(http_parser* header)
|
||||
{
|
||||
memcpy(&_header, header, sizeof(http_parser));
|
||||
}
|
||||
|
||||
void SrsHttpMessage::append_body(const char* body, int length)
|
||||
{
|
||||
_body->append(body, length);
|
||||
}
|
||||
|
||||
string SrsHttpMessage::query_get(string key)
|
||||
{
|
||||
std::string v;
|
||||
|
@ -1052,33 +1199,28 @@ string SrsHttpMessage::query_get(string key)
|
|||
|
||||
int SrsHttpMessage::request_header_count()
|
||||
{
|
||||
return (int)headers.size();
|
||||
return (int)_headers.size();
|
||||
}
|
||||
|
||||
string SrsHttpMessage::request_header_key_at(int index)
|
||||
{
|
||||
srs_assert(index < request_header_count());
|
||||
SrsHttpHeaderField item = headers[index];
|
||||
SrsHttpHeaderField item = _headers[index];
|
||||
return item.first;
|
||||
}
|
||||
|
||||
string SrsHttpMessage::request_header_value_at(int index)
|
||||
{
|
||||
srs_assert(index < request_header_count());
|
||||
SrsHttpHeaderField item = headers[index];
|
||||
SrsHttpHeaderField item = _headers[index];
|
||||
return item.second;
|
||||
}
|
||||
|
||||
void SrsHttpMessage::set_request_header(string key, string value)
|
||||
{
|
||||
headers.push_back(std::make_pair(key, value));
|
||||
}
|
||||
|
||||
string SrsHttpMessage::get_request_header(string name)
|
||||
{
|
||||
std::vector<SrsHttpHeaderField>::iterator it;
|
||||
|
||||
for (it = headers.begin(); it != headers.end(); ++it) {
|
||||
for (it = _headers.begin(); it != _headers.end(); ++it) {
|
||||
SrsHttpHeaderField& elem = *it;
|
||||
std::string key = elem.first;
|
||||
std::string value = elem.second;
|
||||
|
@ -1092,12 +1234,12 @@ string SrsHttpMessage::get_request_header(string name)
|
|||
|
||||
SrsHttpParser::SrsHttpParser()
|
||||
{
|
||||
msg = NULL;
|
||||
buffer = new SrsFastBuffer();
|
||||
}
|
||||
|
||||
SrsHttpParser::~SrsHttpParser()
|
||||
{
|
||||
srs_freep(msg);
|
||||
srs_freep(buffer);
|
||||
}
|
||||
|
||||
int SrsHttpParser::initialize(enum http_parser_type type)
|
||||
|
@ -1125,28 +1267,30 @@ int SrsHttpParser::parse_message(SrsStSocket* skt, SrsHttpMessage** ppmsg)
|
|||
*ppmsg = NULL;
|
||||
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// the msg must be always NULL
|
||||
srs_assert(msg == NULL);
|
||||
msg = new SrsHttpMessage();
|
||||
|
||||
// reset request data.
|
||||
filed_name = "";
|
||||
|
||||
// reset response header.
|
||||
msg->reset();
|
||||
field_value = "";
|
||||
expect_filed_name = true;
|
||||
state = SrsHttpParseStateInit;
|
||||
header = http_parser();
|
||||
url = "";
|
||||
headers.clear();
|
||||
body_parsed = 0;
|
||||
|
||||
// do parse
|
||||
if ((ret = parse_message_imp(skt)) != ERROR_SUCCESS) {
|
||||
if (!srs_is_client_gracefully_close(ret)) {
|
||||
srs_error("parse http msg failed. ret=%d", ret);
|
||||
}
|
||||
srs_freep(msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// create msg
|
||||
SrsHttpMessage* msg = new SrsHttpMessage(skt);
|
||||
|
||||
// initalize http msg, parse url.
|
||||
if ((ret = msg->initialize()) != ERROR_SUCCESS) {
|
||||
if ((ret = msg->update(url, &header, buffer, headers)) != ERROR_SUCCESS) {
|
||||
srs_error("initialize http msg failed. ret=%d", ret);
|
||||
srs_freep(msg);
|
||||
return ret;
|
||||
|
@ -1154,7 +1298,6 @@ int SrsHttpParser::parse_message(SrsStSocket* skt, SrsHttpMessage** ppmsg)
|
|||
|
||||
// parse ok, return the msg.
|
||||
*ppmsg = msg;
|
||||
msg = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1163,42 +1306,52 @@ int SrsHttpParser::parse_message_imp(SrsStSocket* skt)
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// the msg should never be NULL
|
||||
srs_assert(msg != NULL);
|
||||
|
||||
// parser header.
|
||||
char buf[SRS_HTTP_HEADER_BUFFER];
|
||||
for (;;) {
|
||||
ssize_t nread;
|
||||
if ((ret = skt->read(buf, (size_t)sizeof(buf), &nread)) != ERROR_SUCCESS) {
|
||||
if (!srs_is_client_gracefully_close(ret)) {
|
||||
srs_error("read body from server failed. ret=%d", ret);
|
||||
}
|
||||
return ret;
|
||||
while (true) {
|
||||
ssize_t nparsed = 0;
|
||||
|
||||
// when buffer not empty, parse it.
|
||||
if (buffer->size() > 0) {
|
||||
nparsed = http_parser_execute(&parser, &settings, buffer->bytes(), buffer->size());
|
||||
srs_info("buffer=%d, nparsed=%d, body=%d", buffer->size(), (int)nparsed, body_parsed);
|
||||
}
|
||||
|
||||
ssize_t nparsed = http_parser_execute(&parser, &settings, buf, nread);
|
||||
srs_info("read_size=%d, nparsed=%d", (int)nread, (int)nparsed);
|
||||
// consume the parsed bytes.
|
||||
if (nparsed && nparsed - body_parsed > 0) {
|
||||
buffer->read_slice(nparsed - body_parsed);
|
||||
}
|
||||
|
||||
// check header size.
|
||||
if (msg->is_complete()) {
|
||||
return ret;
|
||||
// ok atleast header completed,
|
||||
// never wait for body completed, for maybe chunked.
|
||||
if (state == SrsHttpParseStateHeaderComplete || state == SrsHttpParseStateMessageComplete) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (nparsed != nread) {
|
||||
ret = ERROR_HTTP_PARSE_HEADER;
|
||||
srs_error("parse response error, parsed(%d)!=read(%d), ret=%d", (int)nparsed, (int)nread, ret);
|
||||
return ret;
|
||||
// when nothing parsed, read more to parse.
|
||||
if (nparsed == 0) {
|
||||
// when requires more, only grow 1bytes, but the buffer will cache more.
|
||||
if ((ret = buffer->grow(skt, buffer->size() + 1)) != ERROR_SUCCESS) {
|
||||
if (!srs_is_client_gracefully_close(ret)) {
|
||||
srs_error("read body from server failed. ret=%d", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parse last header.
|
||||
if (!filed_name.empty() && !field_value.empty()) {
|
||||
headers.push_back(std::make_pair(filed_name, field_value));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsHttpParser::on_message_begin(http_parser* parser)
|
||||
{
|
||||
SrsHttpParser* obj = (SrsHttpParser*)parser->data;
|
||||
obj->msg->set_state(SrsHttpParseStateStart);
|
||||
srs_assert(obj);
|
||||
|
||||
obj->state = SrsHttpParseStateStart;
|
||||
|
||||
srs_info("***MESSAGE BEGIN***");
|
||||
|
||||
|
@ -1208,7 +1361,11 @@ int SrsHttpParser::on_message_begin(http_parser* parser)
|
|||
int SrsHttpParser::on_headers_complete(http_parser* parser)
|
||||
{
|
||||
SrsHttpParser* obj = (SrsHttpParser*)parser->data;
|
||||
obj->msg->set_header(parser);
|
||||
srs_assert(obj);
|
||||
|
||||
obj->header = *parser;
|
||||
// save the parser when header parse completed.
|
||||
obj->state = SrsHttpParseStateHeaderComplete;
|
||||
|
||||
srs_info("***HEADERS COMPLETE***");
|
||||
|
||||
|
@ -1219,8 +1376,10 @@ int SrsHttpParser::on_headers_complete(http_parser* parser)
|
|||
int SrsHttpParser::on_message_complete(http_parser* parser)
|
||||
{
|
||||
SrsHttpParser* obj = (SrsHttpParser*)parser->data;
|
||||
// save the parser when header parse completed.
|
||||
obj->msg->set_state(SrsHttpParseStateComplete);
|
||||
srs_assert(obj);
|
||||
|
||||
// save the parser when body parse completed.
|
||||
obj->state = SrsHttpParseStateMessageComplete;
|
||||
|
||||
srs_info("***MESSAGE COMPLETE***\n");
|
||||
|
||||
|
@ -1230,13 +1389,10 @@ int SrsHttpParser::on_message_complete(http_parser* parser)
|
|||
int SrsHttpParser::on_url(http_parser* parser, const char* at, size_t length)
|
||||
{
|
||||
SrsHttpParser* obj = (SrsHttpParser*)parser->data;
|
||||
srs_assert(obj);
|
||||
|
||||
if (length > 0) {
|
||||
std::string url;
|
||||
|
||||
url.append(at, (int)length);
|
||||
|
||||
obj->msg->set_url(url);
|
||||
obj->url.append(at, (int)length);
|
||||
}
|
||||
|
||||
srs_info("Method: %d, Url: %.*s", parser->method, (int)length, at);
|
||||
|
@ -1247,45 +1403,46 @@ int SrsHttpParser::on_url(http_parser* parser, const char* at, size_t length)
|
|||
int SrsHttpParser::on_header_field(http_parser* parser, const char* at, size_t length)
|
||||
{
|
||||
SrsHttpParser* obj = (SrsHttpParser*)parser->data;
|
||||
srs_assert(obj);
|
||||
|
||||
// field value=>name, reap the field.
|
||||
if (!obj->expect_filed_name) {
|
||||
obj->headers.push_back(std::make_pair(obj->filed_name, obj->field_value));
|
||||
|
||||
// reset the field name when parsed.
|
||||
obj->filed_name = "";
|
||||
obj->field_value = "";
|
||||
}
|
||||
obj->expect_filed_name = true;
|
||||
|
||||
if (length > 0) {
|
||||
srs_assert(obj);
|
||||
obj->filed_name.append(at, (int)length);
|
||||
}
|
||||
|
||||
srs_info("Header field: %.*s", (int)length, at);
|
||||
srs_info("Header field(%d bytes): %.*s", (int)length, (int)length, at);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SrsHttpParser::on_header_value(http_parser* parser, const char* at, size_t length)
|
||||
{
|
||||
SrsHttpParser* obj = (SrsHttpParser*)parser->data;
|
||||
srs_assert(obj);
|
||||
|
||||
if (length > 0) {
|
||||
srs_assert(obj);
|
||||
srs_assert(obj->msg);
|
||||
|
||||
std::string field_value;
|
||||
field_value.append(at, (int)length);
|
||||
|
||||
obj->msg->set_request_header(obj->filed_name, field_value);
|
||||
obj->filed_name = "";
|
||||
obj->field_value.append(at, (int)length);
|
||||
}
|
||||
obj->expect_filed_name = false;
|
||||
|
||||
srs_info("Header value: %.*s", (int)length, at);
|
||||
srs_info("Header value(%d bytes): %.*s", (int)length, (int)length, at);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SrsHttpParser::on_body(http_parser* parser, const char* at, size_t length)
|
||||
{
|
||||
SrsHttpParser* obj = (SrsHttpParser*)parser->data;
|
||||
srs_assert(obj);
|
||||
|
||||
if (length > 0) {
|
||||
srs_assert(obj);
|
||||
srs_assert(obj->msg);
|
||||
|
||||
obj->msg->append_body(at, (int)length);
|
||||
}
|
||||
obj->body_parsed += length;
|
||||
|
||||
srs_info("Body: %.*s", (int)length, at);
|
||||
|
||||
|
|
|
@ -47,8 +47,9 @@ class SrsHttpUri;
|
|||
class SrsHttpMessage;
|
||||
class SrsFileReader;
|
||||
class SrsSimpleBuffer;
|
||||
class SrsGoHttpMuxEntry;
|
||||
class ISrsGoHttpResponseWriter;
|
||||
class SrsHttpMuxEntry;
|
||||
class ISrsHttpResponseWriter;
|
||||
class SrsFastBuffer;
|
||||
|
||||
// http specification
|
||||
// CR = <US-ASCII CR, carriage return (13)>
|
||||
|
@ -70,23 +71,24 @@ class ISrsGoHttpResponseWriter;
|
|||
#define __SRS_HTTP_TS_SEND_BUFFER_SIZE 4096
|
||||
|
||||
// helper function: response in json format.
|
||||
extern int srs_go_http_response_json(ISrsGoHttpResponseWriter* w, std::string data);
|
||||
extern int srs_go_http_response_json(ISrsHttpResponseWriter* w, std::string data);
|
||||
|
||||
// state of message
|
||||
enum SrsHttpParseState {
|
||||
SrsHttpParseStateInit = 0,
|
||||
SrsHttpParseStateStart,
|
||||
SrsHttpParseStateComplete
|
||||
SrsHttpParseStateHeaderComplete,
|
||||
SrsHttpParseStateMessageComplete
|
||||
};
|
||||
|
||||
// A Header represents the key-value pairs in an HTTP header.
|
||||
class SrsGoHttpHeader
|
||||
class SrsHttpHeader
|
||||
{
|
||||
private:
|
||||
std::map<std::string, std::string> headers;
|
||||
public:
|
||||
SrsGoHttpHeader();
|
||||
virtual ~SrsGoHttpHeader();
|
||||
SrsHttpHeader();
|
||||
virtual ~SrsHttpHeader();
|
||||
public:
|
||||
// Add adds the key, value pair to the header.
|
||||
// It appends to any existing values associated with key.
|
||||
|
@ -124,7 +126,7 @@ public:
|
|||
// A ResponseWriter interface is used by an HTTP handler to
|
||||
// construct an HTTP response.
|
||||
// Usage 1, response with specified length content:
|
||||
// ISrsGoHttpResponseWriter* w; // create or get response.
|
||||
// ISrsHttpResponseWriter* w; // create or get response.
|
||||
// std::string msg = "Hello, HTTP!";
|
||||
// w->header()->set_content_type("text/plain; charset=utf-8");
|
||||
// w->header()->set_content_length(msg.length());
|
||||
|
@ -132,12 +134,12 @@ public:
|
|||
// w->write((char*)msg.data(), (int)msg.length());
|
||||
// w->final_request(); // optional flush.
|
||||
// Usage 2, response with HTTP code only, zero content length.
|
||||
// ISrsGoHttpResponseWriter* w; // create or get response.
|
||||
// ISrsHttpResponseWriter* w; // create or get response.
|
||||
// w->header()->set_content_length(0);
|
||||
// w->write_header(SRS_CONSTS_HTTP_OK);
|
||||
// w->final_request();
|
||||
// Usage 3, response in chunked encoding.
|
||||
// ISrsGoHttpResponseWriter* w; // create or get response.
|
||||
// ISrsHttpResponseWriter* w; // create or get response.
|
||||
// std::string msg = "Hello, HTTP!";
|
||||
// w->header()->set_content_type("application/octet-stream");
|
||||
// w->write_header(SRS_CONSTS_HTTP_OK);
|
||||
|
@ -146,20 +148,22 @@ public:
|
|||
// w->write((char*)msg.data(), (int)msg.length());
|
||||
// w->write((char*)msg.data(), (int)msg.length());
|
||||
// w->final_request(); // required to end the chunked and flush.
|
||||
class ISrsGoHttpResponseWriter
|
||||
class ISrsHttpResponseWriter
|
||||
{
|
||||
public:
|
||||
ISrsGoHttpResponseWriter();
|
||||
virtual ~ISrsGoHttpResponseWriter();
|
||||
ISrsHttpResponseWriter();
|
||||
virtual ~ISrsHttpResponseWriter();
|
||||
public:
|
||||
// when chunked mode,
|
||||
// final the request to complete the chunked encoding.
|
||||
// for no-chunked mode,
|
||||
// final to send request, for example, content-length is 0.
|
||||
virtual int final_request() = 0;
|
||||
|
||||
// Header returns the header map that will be sent by WriteHeader.
|
||||
// Changing the header after a call to WriteHeader (or Write) has
|
||||
// no effect.
|
||||
virtual SrsGoHttpHeader* header() = 0;
|
||||
virtual SrsHttpHeader* header() = 0;
|
||||
|
||||
// Write writes the data to the connection as part of an HTTP reply.
|
||||
// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
|
||||
|
@ -178,6 +182,26 @@ public:
|
|||
virtual void write_header(int code) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* the reader interface for http response.
|
||||
*/
|
||||
class ISrsHttpResponseReader
|
||||
{
|
||||
public:
|
||||
ISrsHttpResponseReader();
|
||||
virtual ~ISrsHttpResponseReader();
|
||||
public:
|
||||
/**
|
||||
* whether response read EOF.
|
||||
*/
|
||||
virtual bool eof() = 0;
|
||||
/**
|
||||
* read from the response body.
|
||||
* @remark when eof(), return error.
|
||||
*/
|
||||
virtual int read(std::string& data) = 0;
|
||||
};
|
||||
|
||||
// Objects implementing the Handler interface can be
|
||||
// registered to serve a particular path or subtree
|
||||
// in the HTTP server.
|
||||
|
@ -186,38 +210,38 @@ public:
|
|||
// and then return. Returning signals that the request is finished
|
||||
// and that the HTTP server can move on to the next request on
|
||||
// the connection.
|
||||
class ISrsGoHttpHandler
|
||||
class ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoHttpMuxEntry* entry;
|
||||
SrsHttpMuxEntry* entry;
|
||||
public:
|
||||
ISrsGoHttpHandler();
|
||||
virtual ~ISrsGoHttpHandler();
|
||||
ISrsHttpHandler();
|
||||
virtual ~ISrsHttpHandler();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) = 0;
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r) = 0;
|
||||
};
|
||||
|
||||
// Redirect to a fixed URL
|
||||
class SrsGoHttpRedirectHandler : public ISrsGoHttpHandler
|
||||
class SrsHttpRedirectHandler : public ISrsHttpHandler
|
||||
{
|
||||
private:
|
||||
std::string url;
|
||||
int code;
|
||||
public:
|
||||
SrsGoHttpRedirectHandler(std::string u, int c);
|
||||
virtual ~SrsGoHttpRedirectHandler();
|
||||
SrsHttpRedirectHandler(std::string u, int c);
|
||||
virtual ~SrsHttpRedirectHandler();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
// NotFound replies to the request with an HTTP 404 not found error.
|
||||
class SrsGoHttpNotFoundHandler : public ISrsGoHttpHandler
|
||||
class SrsHttpNotFoundHandler : public ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoHttpNotFoundHandler();
|
||||
virtual ~SrsGoHttpNotFoundHandler();
|
||||
SrsHttpNotFoundHandler();
|
||||
virtual ~SrsHttpNotFoundHandler();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
// FileServer returns a handler that serves HTTP requests
|
||||
|
@ -226,54 +250,54 @@ public:
|
|||
// To use the operating system's file system implementation,
|
||||
// use http.Dir:
|
||||
//
|
||||
// http.Handle("/", SrsGoHttpFileServer("/tmp"))
|
||||
// http.Handle("/", SrsGoHttpFileServer("static-dir"))
|
||||
class SrsGoHttpFileServer : public ISrsGoHttpHandler
|
||||
// http.Handle("/", SrsHttpFileServer("/tmp"))
|
||||
// http.Handle("/", SrsHttpFileServer("static-dir"))
|
||||
class SrsHttpFileServer : public ISrsHttpHandler
|
||||
{
|
||||
protected:
|
||||
std::string dir;
|
||||
public:
|
||||
SrsGoHttpFileServer(std::string root_dir);
|
||||
virtual ~SrsGoHttpFileServer();
|
||||
SrsHttpFileServer(std::string root_dir);
|
||||
virtual ~SrsHttpFileServer();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
private:
|
||||
/**
|
||||
* serve the file by specified path
|
||||
*/
|
||||
virtual int serve_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath);
|
||||
virtual int serve_flv_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath);
|
||||
virtual int serve_mp4_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath);
|
||||
virtual int serve_file(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath);
|
||||
virtual int serve_flv_file(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath);
|
||||
virtual int serve_mp4_file(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath);
|
||||
protected:
|
||||
/**
|
||||
* when access flv file with x.flv?start=xxx
|
||||
*/
|
||||
virtual int serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset);
|
||||
virtual int serve_flv_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset);
|
||||
/**
|
||||
* when access mp4 file with x.mp4?range=start-end
|
||||
* @param start the start offset in bytes.
|
||||
* @param end the end offset in bytes. -1 to end of file.
|
||||
* @remark response data in [start, end].
|
||||
*/
|
||||
virtual int serve_mp4_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int start, int end);
|
||||
virtual int serve_mp4_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int start, int end);
|
||||
protected:
|
||||
/**
|
||||
* copy the fs to response writer in size bytes.
|
||||
*/
|
||||
virtual int copy(ISrsGoHttpResponseWriter* w, SrsFileReader* fs, SrsHttpMessage* r, int size);
|
||||
virtual int copy(ISrsHttpResponseWriter* w, SrsFileReader* fs, SrsHttpMessage* r, int size);
|
||||
};
|
||||
|
||||
// the mux entry for server mux.
|
||||
class SrsGoHttpMuxEntry
|
||||
class SrsHttpMuxEntry
|
||||
{
|
||||
public:
|
||||
bool explicit_match;
|
||||
ISrsGoHttpHandler* handler;
|
||||
ISrsHttpHandler* handler;
|
||||
std::string pattern;
|
||||
bool enabled;
|
||||
public:
|
||||
SrsGoHttpMuxEntry();
|
||||
virtual ~SrsGoHttpMuxEntry();
|
||||
SrsHttpMuxEntry();
|
||||
virtual ~SrsHttpMuxEntry();
|
||||
};
|
||||
|
||||
// ServeMux is an HTTP request multiplexer.
|
||||
|
@ -303,16 +327,16 @@ public:
|
|||
// ServeMux also takes care of sanitizing the URL request path,
|
||||
// redirecting any request containing . or .. elements to an
|
||||
// equivalent .- and ..-free URL.
|
||||
class SrsGoHttpServeMux
|
||||
class SrsHttpServeMux
|
||||
{
|
||||
private:
|
||||
// the pattern handler.
|
||||
std::map<std::string, SrsGoHttpMuxEntry*> entries;
|
||||
std::map<std::string, SrsHttpMuxEntry*> entries;
|
||||
// the vhost handler.
|
||||
std::map<std::string, ISrsGoHttpHandler*> vhosts;
|
||||
std::map<std::string, ISrsHttpHandler*> vhosts;
|
||||
public:
|
||||
SrsGoHttpServeMux();
|
||||
virtual ~SrsGoHttpServeMux();
|
||||
SrsHttpServeMux();
|
||||
virtual ~SrsHttpServeMux();
|
||||
public:
|
||||
/**
|
||||
* initialize the http serve mux.
|
||||
|
@ -321,24 +345,24 @@ public:
|
|||
public:
|
||||
// Handle registers the handler for the given pattern.
|
||||
// If a handler already exists for pattern, Handle panics.
|
||||
virtual int handle(std::string pattern, ISrsGoHttpHandler* handler);
|
||||
// interface ISrsGoHttpHandler
|
||||
virtual int handle(std::string pattern, ISrsHttpHandler* handler);
|
||||
// interface ISrsHttpHandler
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
private:
|
||||
virtual int find_handler(SrsHttpMessage* r, ISrsGoHttpHandler** ph);
|
||||
virtual int match(SrsHttpMessage* r, ISrsGoHttpHandler** ph);
|
||||
virtual int find_handler(SrsHttpMessage* r, ISrsHttpHandler** ph);
|
||||
virtual int match(SrsHttpMessage* r, ISrsHttpHandler** ph);
|
||||
virtual bool path_match(std::string pattern, std::string path);
|
||||
};
|
||||
|
||||
/**
|
||||
* response writer use st socket
|
||||
*/
|
||||
class SrsGoHttpResponseWriter : public ISrsGoHttpResponseWriter
|
||||
class SrsHttpResponseWriter : public ISrsHttpResponseWriter
|
||||
{
|
||||
private:
|
||||
SrsStSocket* skt;
|
||||
SrsGoHttpHeader* hdr;
|
||||
SrsHttpHeader* hdr;
|
||||
private:
|
||||
// reply header has been (logically) written
|
||||
bool header_wrote;
|
||||
|
@ -356,16 +380,47 @@ private:
|
|||
// logically written.
|
||||
bool header_sent;
|
||||
public:
|
||||
SrsGoHttpResponseWriter(SrsStSocket* io);
|
||||
virtual ~SrsGoHttpResponseWriter();
|
||||
SrsHttpResponseWriter(SrsStSocket* io);
|
||||
virtual ~SrsHttpResponseWriter();
|
||||
public:
|
||||
virtual int final_request();
|
||||
virtual SrsGoHttpHeader* header();
|
||||
virtual SrsHttpHeader* header();
|
||||
virtual int write(char* data, int size);
|
||||
virtual void write_header(int code);
|
||||
virtual int send_header(char* data, int size);
|
||||
};
|
||||
|
||||
/**
|
||||
* response reader use st socket.
|
||||
*/
|
||||
class SrsHttpResponseReader : virtual public ISrsHttpResponseReader
|
||||
{
|
||||
private:
|
||||
SrsStSocket* skt;
|
||||
SrsHttpMessage* owner;
|
||||
SrsFastBuffer* buffer;
|
||||
bool is_eof;
|
||||
int64_t nb_read;
|
||||
public:
|
||||
SrsHttpResponseReader(SrsHttpMessage* msg, SrsStSocket* io);
|
||||
virtual ~SrsHttpResponseReader();
|
||||
public:
|
||||
/**
|
||||
* initialize the response reader with buffer.
|
||||
*/
|
||||
virtual int initialize(SrsFastBuffer* buffer);
|
||||
// interface ISrsHttpResponseReader
|
||||
public:
|
||||
virtual bool eof();
|
||||
virtual int read(std::string& data);
|
||||
private:
|
||||
virtual int read_chunked(std::string& data);
|
||||
virtual int read_specified(int max, std::string& data);
|
||||
};
|
||||
|
||||
// for http header.
|
||||
typedef std::pair<std::string, std::string> SrsHttpHeaderField;
|
||||
|
||||
// A Request represents an HTTP request received by a server
|
||||
// or to be sent by a client.
|
||||
//
|
||||
|
@ -387,15 +442,14 @@ private:
|
|||
*/
|
||||
http_parser _header;
|
||||
/**
|
||||
* body object, in bytes.
|
||||
* body object, reader object.
|
||||
* @remark, user can get body in string by get_body().
|
||||
*/
|
||||
SrsSimpleBuffer* _body;
|
||||
SrsHttpResponseReader* _body;
|
||||
/**
|
||||
* parser state
|
||||
* @remark, user can use is_complete() to determine the state.
|
||||
* whether the body is chunked.
|
||||
*/
|
||||
SrsHttpParseState _state;
|
||||
bool chunked;
|
||||
/**
|
||||
* uri parser
|
||||
*/
|
||||
|
@ -403,53 +457,77 @@ private:
|
|||
/**
|
||||
* use a buffer to read and send ts file.
|
||||
*/
|
||||
// TODO: FIXME: remove it.
|
||||
char* _http_ts_send_buffer;
|
||||
// http headers
|
||||
typedef std::pair<std::string, std::string> SrsHttpHeaderField;
|
||||
std::vector<SrsHttpHeaderField> headers;
|
||||
std::vector<SrsHttpHeaderField> _headers;
|
||||
// the query map
|
||||
std::map<std::string, std::string> _query;
|
||||
public:
|
||||
SrsHttpMessage();
|
||||
SrsHttpMessage(SrsStSocket* io);
|
||||
virtual ~SrsHttpMessage();
|
||||
public:
|
||||
virtual int initialize();
|
||||
/**
|
||||
* set the original messages, then update the message.
|
||||
*/
|
||||
virtual int update(std::string url, http_parser* header,
|
||||
SrsFastBuffer* body, std::vector<SrsHttpHeaderField>& headers
|
||||
);
|
||||
public:
|
||||
virtual char* http_ts_send_buffer();
|
||||
virtual void reset();
|
||||
public:
|
||||
virtual bool is_complete();
|
||||
virtual u_int8_t method();
|
||||
virtual u_int16_t status_code();
|
||||
/**
|
||||
* method helpers.
|
||||
*/
|
||||
virtual std::string method_str();
|
||||
virtual bool is_http_get();
|
||||
virtual bool is_http_put();
|
||||
virtual bool is_http_post();
|
||||
virtual bool is_http_delete();
|
||||
virtual bool is_http_options();
|
||||
/**
|
||||
* whether body is chunked encoding, for reader only.
|
||||
*/
|
||||
virtual bool is_chunked();
|
||||
/**
|
||||
* the uri contains the host and path.
|
||||
*/
|
||||
virtual std::string uri();
|
||||
/**
|
||||
* the url maybe the path.
|
||||
*/
|
||||
virtual std::string url();
|
||||
virtual std::string host();
|
||||
virtual std::string path();
|
||||
public:
|
||||
virtual std::string body();
|
||||
virtual char* body_raw();
|
||||
virtual int64_t body_size();
|
||||
/**
|
||||
* read body to string.
|
||||
* @remark for small http body.
|
||||
*/
|
||||
virtual int body_read_all(std::string& body);
|
||||
/**
|
||||
* get the body reader, to read one by one.
|
||||
* @remark when body is very large, or chunked, use this.
|
||||
*/
|
||||
virtual ISrsHttpResponseReader* body_reader();
|
||||
/**
|
||||
* the content length, -1 for chunked or not set.
|
||||
*/
|
||||
virtual int64_t content_length();
|
||||
virtual void set_url(std::string url);
|
||||
virtual void set_state(SrsHttpParseState state);
|
||||
virtual void set_header(http_parser* header);
|
||||
virtual void append_body(const char* body, int length);
|
||||
/**
|
||||
* get the param in query string,
|
||||
* for instance, query is "start=100&end=200",
|
||||
* then query_get("start") is "100", and query_get("end") is "200"
|
||||
*/
|
||||
virtual std::string query_get(std::string key);
|
||||
/**
|
||||
* get the headers.
|
||||
*/
|
||||
virtual int request_header_count();
|
||||
virtual std::string request_header_key_at(int index);
|
||||
virtual std::string request_header_value_at(int index);
|
||||
virtual void set_request_header(std::string key, std::string value);
|
||||
virtual std::string get_request_header(std::string name);
|
||||
};
|
||||
|
||||
|
@ -462,8 +540,18 @@ class SrsHttpParser
|
|||
private:
|
||||
http_parser_settings settings;
|
||||
http_parser parser;
|
||||
SrsHttpMessage* msg;
|
||||
// the global parse buffer.
|
||||
SrsFastBuffer* buffer;
|
||||
private:
|
||||
// http parse data, reset before parse message.
|
||||
bool expect_filed_name;
|
||||
std::string filed_name;
|
||||
std::string field_value;
|
||||
SrsHttpParseState state;
|
||||
http_parser header;
|
||||
std::string url;
|
||||
std::vector<SrsHttpHeaderField> headers;
|
||||
int body_parsed;
|
||||
public:
|
||||
SrsHttpParser();
|
||||
virtual ~SrsHttpParser();
|
||||
|
|
|
@ -48,7 +48,7 @@ SrsGoApiRoot::~SrsGoApiRoot()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiRoot::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiRoot::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -70,7 +70,7 @@ SrsGoApiApi::~SrsGoApiApi()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiApi::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiApi::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -92,7 +92,7 @@ SrsGoApiV1::~SrsGoApiV1()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiV1::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiV1::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -108,8 +108,7 @@ int SrsGoApiV1::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
|||
<< __SRS_JFIELD_STR("authors", "the primary authors and contributors") << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("requests", "the request itself, for http debug") << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("vhosts", "dumps vhost to json") << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("streams", "dumps streams to json") << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("dvrs", "query or control the dvr plan")
|
||||
<< __SRS_JFIELD_STR("streams", "dumps streams to json")
|
||||
<< __SRS_JOBJECT_END
|
||||
<< __SRS_JOBJECT_END;
|
||||
|
||||
|
@ -124,7 +123,7 @@ SrsGoApiVersion::~SrsGoApiVersion()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiVersion::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiVersion::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -149,7 +148,7 @@ SrsGoApiSummaries::~SrsGoApiSummaries()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiSummaries::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiSummaries::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
srs_api_dump_summaries(ss);
|
||||
|
@ -164,7 +163,7 @@ SrsGoApiRusages::~SrsGoApiRusages()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiRusages::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* req)
|
||||
int SrsGoApiRusages::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* req)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -205,7 +204,7 @@ SrsGoApiSelfProcStats::~SrsGoApiSelfProcStats()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiSelfProcStats::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiSelfProcStats::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -275,7 +274,7 @@ SrsGoApiSystemProcStats::~SrsGoApiSystemProcStats()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiSystemProcStats::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiSystemProcStats::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -310,7 +309,7 @@ SrsGoApiMemInfos::~SrsGoApiMemInfos()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiMemInfos::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiMemInfos::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -346,7 +345,7 @@ SrsGoApiAuthors::~SrsGoApiAuthors()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiAuthors::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiAuthors::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -371,7 +370,7 @@ SrsGoApiRequests::~SrsGoApiRequests()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiRequests::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiRequests::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
SrsHttpMessage* req = r;
|
||||
|
||||
|
@ -432,7 +431,7 @@ SrsGoApiVhosts::~SrsGoApiVhosts()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiVhosts::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiVhosts::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream data;
|
||||
SrsStatistic* stat = SrsStatistic::instance();
|
||||
|
@ -457,7 +456,7 @@ SrsGoApiStreams::~SrsGoApiStreams()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiStreams::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream data;
|
||||
SrsStatistic* stat = SrsStatistic::instance();
|
||||
|
@ -474,77 +473,7 @@ int SrsGoApiStreams::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
|||
return srs_go_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsGoApiDvrs::SrsGoApiDvrs()
|
||||
{
|
||||
}
|
||||
|
||||
SrsGoApiDvrs::~SrsGoApiDvrs()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
#ifndef SRS_AUTO_DVR
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_ERROR(ERROR_HTTP_DVR_DISABLED)
|
||||
<< __SRS_JOBJECT_END;
|
||||
#else
|
||||
SrsApiDvrPool* pool = SrsApiDvrPool::instance();
|
||||
if (r->is_http_get()) {
|
||||
std::stringstream data;
|
||||
int ret = pool->dumps(r->query_get("vhost"), data);
|
||||
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_ERROR(ret) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("dvrs", data.str())
|
||||
<< __SRS_JOBJECT_END;
|
||||
} else if (r->is_http_post()) {
|
||||
std::string body = r->body();
|
||||
SrsJsonAny* json = SrsJsonAny::loads((char*)body.c_str());
|
||||
int ret = ERROR_SUCCESS;
|
||||
if (!json) {
|
||||
ret = ERROR_HTTP_JSON_REQUIRED;
|
||||
} else {
|
||||
SrsAutoFree(SrsJsonAny, json);
|
||||
ret = pool->create(json);
|
||||
}
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_ERROR(ret)
|
||||
<< __SRS_JOBJECT_END;
|
||||
} else if (r->is_http_delete()) {
|
||||
int ret = pool->stop(r->query_get("vhost"));
|
||||
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_ERROR(ret)
|
||||
<< __SRS_JOBJECT_END;
|
||||
} else if (r->is_http_put()) {
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
std::string body = r->body();
|
||||
SrsJsonAny* json = SrsJsonAny::loads((char*)body.c_str());
|
||||
if (!json) {
|
||||
ret = ERROR_HTTP_JSON_REQUIRED;
|
||||
} else {
|
||||
SrsAutoFree(SrsJsonAny, json);
|
||||
ret = pool->rpc(json);
|
||||
}
|
||||
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_ERROR(ret)
|
||||
<< __SRS_JOBJECT_END;
|
||||
} else {
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_ERROR(ERROR_HTTP_DVR_REQUEST)
|
||||
<< __SRS_JOBJECT_END;
|
||||
}
|
||||
#endif
|
||||
|
||||
return srs_go_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsHttpApi::SrsHttpApi(SrsServer* svr, st_netfd_t fd, SrsGoHttpServeMux* m)
|
||||
SrsHttpApi::SrsHttpApi(SrsServer* svr, st_netfd_t fd, SrsHttpServeMux* m)
|
||||
: SrsConnection(svr, fd)
|
||||
{
|
||||
mux = m;
|
||||
|
@ -557,7 +486,7 @@ SrsHttpApi::~SrsHttpApi()
|
|||
srs_freep(parser);
|
||||
}
|
||||
|
||||
void SrsHttpApi::kbps_resample()
|
||||
void SrsHttpApi::resample()
|
||||
{
|
||||
// TODO: FIXME: implements it
|
||||
}
|
||||
|
@ -574,6 +503,11 @@ int64_t SrsHttpApi::get_recv_bytes_delta()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void SrsHttpApi::cleanup()
|
||||
{
|
||||
// TODO: FIXME: implements it
|
||||
}
|
||||
|
||||
int SrsHttpApi::do_cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
@ -598,15 +532,22 @@ int SrsHttpApi::do_cycle()
|
|||
return ret;
|
||||
}
|
||||
|
||||
// if SUCCESS, always NOT-NULL and completed message.
|
||||
// if SUCCESS, always NOT-NULL.
|
||||
srs_assert(req);
|
||||
srs_assert(req->is_complete());
|
||||
|
||||
// always free it in this scope.
|
||||
SrsAutoFree(SrsHttpMessage, req);
|
||||
|
||||
// TODO: FIXME: use the post body.
|
||||
std::string res;
|
||||
|
||||
// get response body.
|
||||
if ((ret = req->body_read_all(res)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ok, handle http request.
|
||||
SrsGoHttpResponseWriter writer(&skt);
|
||||
SrsHttpResponseWriter writer(&skt);
|
||||
if ((ret = process_request(&writer, req)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -615,7 +556,7 @@ int SrsHttpApi::do_cycle()
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsHttpApi::process_request(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsHttpApi::process_request(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
|
|
@ -42,151 +42,142 @@ class SrsHttpHandler;
|
|||
#include <srs_app_http.hpp>
|
||||
|
||||
// for http root.
|
||||
class SrsGoApiRoot : public ISrsGoHttpHandler
|
||||
class SrsGoApiRoot : public ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoApiRoot();
|
||||
virtual ~SrsGoApiRoot();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiApi : public ISrsGoHttpHandler
|
||||
class SrsGoApiApi : public ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoApiApi();
|
||||
virtual ~SrsGoApiApi();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiV1 : public ISrsGoHttpHandler
|
||||
class SrsGoApiV1 : public ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoApiV1();
|
||||
virtual ~SrsGoApiV1();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiVersion : public ISrsGoHttpHandler
|
||||
class SrsGoApiVersion : public ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoApiVersion();
|
||||
virtual ~SrsGoApiVersion();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiSummaries : public ISrsGoHttpHandler
|
||||
class SrsGoApiSummaries : public ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoApiSummaries();
|
||||
virtual ~SrsGoApiSummaries();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiRusages : public ISrsGoHttpHandler
|
||||
class SrsGoApiRusages : public ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoApiRusages();
|
||||
virtual ~SrsGoApiRusages();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiSelfProcStats : public ISrsGoHttpHandler
|
||||
class SrsGoApiSelfProcStats : public ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoApiSelfProcStats();
|
||||
virtual ~SrsGoApiSelfProcStats();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiSystemProcStats : public ISrsGoHttpHandler
|
||||
class SrsGoApiSystemProcStats : public ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoApiSystemProcStats();
|
||||
virtual ~SrsGoApiSystemProcStats();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiMemInfos : public ISrsGoHttpHandler
|
||||
class SrsGoApiMemInfos : public ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoApiMemInfos();
|
||||
virtual ~SrsGoApiMemInfos();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiAuthors : public ISrsGoHttpHandler
|
||||
class SrsGoApiAuthors : public ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoApiAuthors();
|
||||
virtual ~SrsGoApiAuthors();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiRequests : public ISrsGoHttpHandler
|
||||
class SrsGoApiRequests : public ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoApiRequests();
|
||||
virtual ~SrsGoApiRequests();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiVhosts : public ISrsGoHttpHandler
|
||||
class SrsGoApiVhosts : public ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoApiVhosts();
|
||||
virtual ~SrsGoApiVhosts();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiStreams : public ISrsGoHttpHandler
|
||||
class SrsGoApiStreams : public ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoApiStreams();
|
||||
virtual ~SrsGoApiStreams();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiDvrs : public ISrsGoHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoApiDvrs();
|
||||
virtual ~SrsGoApiDvrs();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsHttpApi : public SrsConnection
|
||||
{
|
||||
private:
|
||||
SrsHttpParser* parser;
|
||||
SrsGoHttpServeMux* mux;
|
||||
SrsHttpServeMux* mux;
|
||||
bool crossdomain_required;
|
||||
public:
|
||||
SrsHttpApi(SrsServer* svr, st_netfd_t fd, SrsGoHttpServeMux* m);
|
||||
SrsHttpApi(SrsServer* svr, st_netfd_t fd, SrsHttpServeMux* m);
|
||||
virtual ~SrsHttpApi();
|
||||
public:
|
||||
virtual void kbps_resample();
|
||||
// interface IKbpsDelta
|
||||
public:
|
||||
virtual void resample();
|
||||
virtual int64_t get_send_bytes_delta();
|
||||
virtual int64_t get_recv_bytes_delta();
|
||||
virtual void cleanup();
|
||||
protected:
|
||||
virtual int do_cycle();
|
||||
private:
|
||||
virtual int process_request(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int process_request(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -35,6 +35,7 @@ using namespace std;
|
|||
#include <srs_app_st_socket.hpp>
|
||||
#include <srs_kernel_utility.hpp>
|
||||
#include <srs_app_utility.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
|
||||
// when error, http client sleep for a while and retry.
|
||||
#define SRS_HTTP_CLIENT_SLEEP_US (int64_t)(3*1000*1000LL)
|
||||
|
@ -43,6 +44,7 @@ SrsHttpClient::SrsHttpClient()
|
|||
{
|
||||
connected = false;
|
||||
stfd = NULL;
|
||||
skt = NULL;
|
||||
parser = NULL;
|
||||
}
|
||||
|
||||
|
@ -52,22 +54,31 @@ SrsHttpClient::~SrsHttpClient()
|
|||
srs_freep(parser);
|
||||
}
|
||||
|
||||
int SrsHttpClient::post(SrsHttpUri* uri, string req, int& status_code, string& res)
|
||||
int SrsHttpClient::initialize(string h, int p)
|
||||
{
|
||||
res = "";
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
srs_freep(parser);
|
||||
parser = new SrsHttpParser();
|
||||
|
||||
if ((ret = parser->initialize(HTTP_RESPONSE)) != ERROR_SUCCESS) {
|
||||
srs_error("initialize parser failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
host = h;
|
||||
port = p;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsHttpClient::post(string path, string req, SrsHttpMessage** ppmsg)
|
||||
{
|
||||
*ppmsg = NULL;
|
||||
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (!parser) {
|
||||
parser = new SrsHttpParser();
|
||||
|
||||
if ((ret = parser->initialize(HTTP_RESPONSE)) != ERROR_SUCCESS) {
|
||||
srs_error("initialize parser failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ret = connect(uri)) != ERROR_SUCCESS) {
|
||||
if ((ret = connect()) != ERROR_SUCCESS) {
|
||||
srs_warn("http connect server failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -75,9 +86,9 @@ int SrsHttpClient::post(SrsHttpUri* uri, string req, int& status_code, string& r
|
|||
// send POST request to uri
|
||||
// POST %s HTTP/1.1\r\nHost: %s\r\nContent-Length: %d\r\n\r\n%s
|
||||
std::stringstream ss;
|
||||
ss << "POST " << uri->get_path() << " "
|
||||
ss << "POST " << path << " "
|
||||
<< "HTTP/1.1" << __SRS_HTTP_CRLF
|
||||
<< "Host: " << uri->get_host() << __SRS_HTTP_CRLF
|
||||
<< "Host: " << host << __SRS_HTTP_CRLF
|
||||
<< "Connection: Keep-Alive" << __SRS_HTTP_CRLF
|
||||
<< "Content-Length: " << std::dec << req.length() << __SRS_HTTP_CRLF
|
||||
<< "User-Agent: " << RTMP_SIG_SRS_NAME << RTMP_SIG_SRS_VERSION << __SRS_HTTP_CRLF
|
||||
|
@ -85,10 +96,8 @@ int SrsHttpClient::post(SrsHttpUri* uri, string req, int& status_code, string& r
|
|||
<< __SRS_HTTP_CRLF
|
||||
<< req;
|
||||
|
||||
SrsStSocket skt(stfd);
|
||||
|
||||
std::string data = ss.str();
|
||||
if ((ret = skt.write((void*)data.c_str(), data.length(), NULL)) != ERROR_SUCCESS) {
|
||||
if ((ret = skt->write((void*)data.c_str(), data.length(), NULL)) != ERROR_SUCCESS) {
|
||||
// disconnect when error.
|
||||
disconnect();
|
||||
|
||||
|
@ -97,24 +106,61 @@ int SrsHttpClient::post(SrsHttpUri* uri, string req, int& status_code, string& r
|
|||
}
|
||||
|
||||
SrsHttpMessage* msg = NULL;
|
||||
if ((ret = parser->parse_message(&skt, &msg)) != ERROR_SUCCESS) {
|
||||
if ((ret = parser->parse_message(skt, &msg)) != ERROR_SUCCESS) {
|
||||
srs_error("parse http post response failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
srs_assert(msg);
|
||||
srs_assert(msg->is_complete());
|
||||
|
||||
status_code = (int)msg->status_code();
|
||||
|
||||
// get response body.
|
||||
if (msg->body_size() > 0) {
|
||||
res = msg->body();
|
||||
}
|
||||
*ppmsg = msg;
|
||||
srs_info("parse http post response success.");
|
||||
|
||||
srs_freep(msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsHttpClient::get(string path, std::string req, SrsHttpMessage** ppmsg)
|
||||
{
|
||||
*ppmsg = NULL;
|
||||
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if ((ret = connect()) != ERROR_SUCCESS) {
|
||||
srs_warn("http connect server failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// send POST request to uri
|
||||
// GET %s HTTP/1.1\r\nHost: %s\r\nContent-Length: %d\r\n\r\n%s
|
||||
std::stringstream ss;
|
||||
ss << "GET " << path << " "
|
||||
<< "HTTP/1.1" << __SRS_HTTP_CRLF
|
||||
<< "Host: " << host << __SRS_HTTP_CRLF
|
||||
<< "Connection: Keep-Alive" << __SRS_HTTP_CRLF
|
||||
<< "Content-Length: " << std::dec << req.length() << __SRS_HTTP_CRLF
|
||||
<< "User-Agent: " << RTMP_SIG_SRS_NAME << RTMP_SIG_SRS_VERSION << __SRS_HTTP_CRLF
|
||||
<< "Content-Type: application/json" << __SRS_HTTP_CRLF
|
||||
<< __SRS_HTTP_CRLF
|
||||
<< req;
|
||||
|
||||
std::string data = ss.str();
|
||||
if ((ret = skt->write((void*)data.c_str(), data.length(), NULL)) != ERROR_SUCCESS) {
|
||||
// disconnect when error.
|
||||
disconnect();
|
||||
|
||||
srs_error("write http get failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsHttpMessage* msg = NULL;
|
||||
if ((ret = parser->parse_message(skt, &msg)) != ERROR_SUCCESS) {
|
||||
srs_error("parse http post response failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
srs_assert(msg);
|
||||
|
||||
*ppmsg = msg;
|
||||
srs_info("parse http get response success.");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -123,9 +169,10 @@ void SrsHttpClient::disconnect()
|
|||
connected = false;
|
||||
|
||||
srs_close_stfd(stfd);
|
||||
srs_freep(skt);
|
||||
}
|
||||
|
||||
int SrsHttpClient::connect(SrsHttpUri* uri)
|
||||
int SrsHttpClient::connect()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -135,19 +182,17 @@ int SrsHttpClient::connect(SrsHttpUri* uri)
|
|||
|
||||
disconnect();
|
||||
|
||||
std::string server = uri->get_host();
|
||||
int port = uri->get_port();
|
||||
|
||||
// open socket.
|
||||
int64_t timeout = SRS_HTTP_CLIENT_SLEEP_US;
|
||||
if ((ret = srs_socket_connect(server, port, timeout, &stfd)) != ERROR_SUCCESS) {
|
||||
if ((ret = srs_socket_connect(host, port, timeout, &stfd)) != ERROR_SUCCESS) {
|
||||
srs_warn("http client failed, server=%s, port=%d, timeout=%"PRId64", ret=%d",
|
||||
server.c_str(), port, timeout, ret);
|
||||
host.c_str(), port, timeout, ret);
|
||||
return ret;
|
||||
}
|
||||
srs_info("connect to server success. http url=%s, server=%s, port=%d",
|
||||
uri->get_url(), uri->get_host(), uri->get_port());
|
||||
srs_info("connect to server success. server=%s, port=%d", host, port);
|
||||
|
||||
srs_assert(!skt);
|
||||
skt = new SrsStSocket(stfd);
|
||||
connected = true;
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -37,6 +37,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
class SrsHttpUri;
|
||||
class SrsHttpParser;
|
||||
class SrsHttpMessage;
|
||||
class SrsStSocket;
|
||||
|
||||
/**
|
||||
* http client to GET/POST/PUT/DELETE uri
|
||||
|
@ -46,21 +48,38 @@ class SrsHttpClient
|
|||
private:
|
||||
bool connected;
|
||||
st_netfd_t stfd;
|
||||
SrsStSocket* skt;
|
||||
SrsHttpParser* parser;
|
||||
private:
|
||||
// host name or ip.
|
||||
std::string host;
|
||||
int port;
|
||||
public:
|
||||
SrsHttpClient();
|
||||
virtual ~SrsHttpClient();
|
||||
public:
|
||||
/**
|
||||
* to post data to the uri.
|
||||
* @param req the data post to uri.
|
||||
* @param status_code the output status code response by server.
|
||||
* @param res output the response data from server.
|
||||
* initialize the client, connect to host and port.
|
||||
*/
|
||||
virtual int post(SrsHttpUri* uri, std::string req, int& status_code, std::string& res);
|
||||
virtual int initialize(std::string h, int p);
|
||||
public:
|
||||
/**
|
||||
* to post data to the uri.
|
||||
* @param the path to request on.
|
||||
* @param req the data post to uri. empty string to ignore.
|
||||
* @param ppmsg output the http message to read the response.
|
||||
*/
|
||||
virtual int post(std::string path, std::string req, SrsHttpMessage** ppmsg);
|
||||
/**
|
||||
* to get data from the uri.
|
||||
* @param the path to request on.
|
||||
* @param req the data post to uri. empty string to ignore.
|
||||
* @param ppmsg output the http message to read the response.
|
||||
*/
|
||||
virtual int get(std::string path, std::string req, SrsHttpMessage** ppmsg);
|
||||
private:
|
||||
virtual void disconnect();
|
||||
virtual int connect(SrsHttpUri* uri);
|
||||
virtual int connect();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -50,7 +50,7 @@ using namespace std;
|
|||
#include <srs_app_pithy_print.hpp>
|
||||
|
||||
SrsVodStream::SrsVodStream(string root_dir)
|
||||
: SrsGoHttpFileServer(root_dir)
|
||||
: SrsHttpFileServer(root_dir)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ SrsVodStream::~SrsVodStream()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsVodStream::serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int offset)
|
||||
int SrsVodStream::serve_flv_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int offset)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -142,7 +142,7 @@ int SrsVodStream::serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage*
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsVodStream::serve_mp4_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int start, int end)
|
||||
int SrsVodStream::serve_mp4_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, string fullpath, int start, int end)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -394,7 +394,7 @@ int SrsFlvStreamEncoder::write_video(int64_t timestamp, char* data, int size)
|
|||
|
||||
int SrsFlvStreamEncoder::write_metadata(int64_t timestamp, char* data, int size)
|
||||
{
|
||||
return enc->write_metadata(timestamp, data, size);
|
||||
return enc->write_metadata(SrsCodecFlvTagScript, data, size);
|
||||
}
|
||||
|
||||
bool SrsFlvStreamEncoder::has_cache()
|
||||
|
@ -517,7 +517,7 @@ int SrsMp3StreamEncoder::dump_cache(SrsConsumer* consumer)
|
|||
return cache->dump_cache(consumer);
|
||||
}
|
||||
|
||||
SrsStreamWriter::SrsStreamWriter(ISrsGoHttpResponseWriter* w)
|
||||
SrsStreamWriter::SrsStreamWriter(ISrsHttpResponseWriter* w)
|
||||
{
|
||||
writer = w;
|
||||
}
|
||||
|
@ -565,7 +565,7 @@ SrsLiveStream::~SrsLiveStream()
|
|||
srs_freep(req);
|
||||
}
|
||||
|
||||
int SrsLiveStream::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsLiveStream::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -708,7 +708,7 @@ void SrsHlsM3u8Stream::set_m3u8(std::string v)
|
|||
m3u8 = v;
|
||||
}
|
||||
|
||||
int SrsHlsM3u8Stream::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsHlsM3u8Stream::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -740,7 +740,7 @@ void SrsHlsTsStream::set_ts(std::string v)
|
|||
ts = v;
|
||||
}
|
||||
|
||||
int SrsHlsTsStream::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsHlsTsStream::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -771,19 +771,35 @@ SrsHttpServer::~SrsHttpServer()
|
|||
{
|
||||
if (true) {
|
||||
std::map<std::string, SrsLiveEntry*>::iterator it;
|
||||
for (it = flvs.begin(); it != flvs.end(); ++it) {
|
||||
for (it = tflvs.begin(); it != tflvs.end(); ++it) {
|
||||
SrsLiveEntry* entry = it->second;
|
||||
srs_freep(entry);
|
||||
}
|
||||
flvs.clear();
|
||||
tflvs.clear();
|
||||
}
|
||||
if (true) {
|
||||
std::map<std::string, SrsLiveEntry*>::iterator it;
|
||||
for (it = sflvs.begin(); it != sflvs.end(); ++it) {
|
||||
SrsLiveEntry* entry = it->second;
|
||||
srs_freep(entry);
|
||||
}
|
||||
sflvs.clear();
|
||||
}
|
||||
if (true) {
|
||||
std::map<std::string, SrsHlsEntry*>::iterator it;
|
||||
for (it = hls.begin(); it != hls.end(); ++it) {
|
||||
for (it = thls.begin(); it != thls.end(); ++it) {
|
||||
SrsHlsEntry* entry = it->second;
|
||||
srs_freep(entry);
|
||||
}
|
||||
hls.clear();
|
||||
thls.clear();
|
||||
}
|
||||
if (true) {
|
||||
std::map<std::string, SrsHlsEntry*>::iterator it;
|
||||
for (it = shls.begin(); it != shls.end(); ++it) {
|
||||
SrsHlsEntry* entry = it->second;
|
||||
srs_freep(entry);
|
||||
}
|
||||
shls.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -814,56 +830,72 @@ int SrsHttpServer::mount(SrsSource* s, SrsRequest* r)
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (flvs.find(r->vhost) == flvs.end()) {
|
||||
srs_info("ignore mount flv stream for disabled");
|
||||
return ret;
|
||||
}
|
||||
// the id to identify stream.
|
||||
std::string sid = r->get_stream_url();
|
||||
SrsLiveEntry* entry = NULL;
|
||||
|
||||
SrsLiveEntry* entry = flvs[r->vhost];
|
||||
// create stream from template when not found.
|
||||
if (sflvs.find(sid) == sflvs.end()) {
|
||||
if (tflvs.find(r->vhost) == tflvs.end()) {
|
||||
srs_info("ignore mount flv stream for disabled");
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsLiveEntry* tmpl = tflvs[r->vhost];
|
||||
|
||||
std::string mount = tmpl->mount;
|
||||
|
||||
// replace the vhost variable
|
||||
mount = srs_string_replace(mount, "[vhost]", r->vhost);
|
||||
mount = srs_string_replace(mount, "[app]", r->app);
|
||||
mount = srs_string_replace(mount, "[stream]", r->stream);
|
||||
|
||||
// remove the default vhost mount
|
||||
mount = srs_string_replace(mount, SRS_CONSTS_RTMP_DEFAULT_VHOST"/", "/");
|
||||
|
||||
entry = new SrsLiveEntry();
|
||||
entry->mount = mount;
|
||||
|
||||
entry->cache = new SrsStreamCache(s, r);
|
||||
entry->stream = new SrsLiveStream(s, r, entry->cache);
|
||||
|
||||
sflvs[sid] = entry;
|
||||
|
||||
// start http stream cache thread
|
||||
if ((ret = entry->cache->start()) != ERROR_SUCCESS) {
|
||||
srs_error("http: start stream cache failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// mount the http flv stream.
|
||||
if ((ret = mux.handle(mount, entry->stream)) != ERROR_SUCCESS) {
|
||||
srs_error("http: mount flv stream for vhost=%s failed. ret=%d", sid.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
srs_trace("http: mount flv stream for vhost=%s, mount=%s", sid.c_str(), mount.c_str());
|
||||
} else {
|
||||
entry = sflvs[sid];
|
||||
}
|
||||
|
||||
// TODO: FIXME: supports reload.
|
||||
if (entry->stream) {
|
||||
entry->stream->entry->enabled = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string mount = entry->mount;
|
||||
|
||||
// replace the vhost variable
|
||||
mount = srs_string_replace(mount, "[vhost]", r->vhost);
|
||||
mount = srs_string_replace(mount, "[app]", r->app);
|
||||
mount = srs_string_replace(mount, "[stream]", r->stream);
|
||||
|
||||
// remove the default vhost mount
|
||||
mount = srs_string_replace(mount, SRS_CONSTS_RTMP_DEFAULT_VHOST"/", "/");
|
||||
|
||||
entry->cache = new SrsStreamCache(s, r);
|
||||
entry->stream = new SrsLiveStream(s, r, entry->cache);
|
||||
|
||||
// start http stream cache thread
|
||||
if ((ret = entry->cache->start()) != ERROR_SUCCESS) {
|
||||
srs_error("http: start stream cache failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// mount the http flv stream.
|
||||
if ((ret = mux.handle(mount, entry->stream)) != ERROR_SUCCESS) {
|
||||
srs_error("http: mount flv stream for vhost=%s failed. ret=%d", r->vhost.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
srs_trace("http: mount flv stream for vhost=%s, mount=%s", r->vhost.c_str(), mount.c_str());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SrsHttpServer::unmount(SrsSource* s, SrsRequest* r)
|
||||
{
|
||||
if (flvs.find(r->vhost) == flvs.end()) {
|
||||
std::string sid = r->get_stream_url();
|
||||
|
||||
if (sflvs.find(sid) == sflvs.end()) {
|
||||
srs_info("ignore unmount flv stream for disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
SrsLiveEntry* entry = flvs[r->vhost];
|
||||
SrsLiveEntry* entry = sflvs[sid];
|
||||
entry->stream->entry->enabled = false;
|
||||
}
|
||||
|
||||
|
@ -871,17 +903,19 @@ int SrsHttpServer::mount_hls(SrsRequest* r)
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (hls.find(r->vhost) == hls.end()) {
|
||||
std::string sid = r->get_stream_url();
|
||||
|
||||
if (shls.find(sid) == shls.end()) {
|
||||
srs_info("ignore mount hls stream for disabled");
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsHlsEntry* entry = hls[r->vhost];
|
||||
SrsHlsEntry* entry = shls[sid];
|
||||
|
||||
// TODO: FIXME: supports reload.
|
||||
std::map<std::string, ISrsGoHttpHandler*>::iterator it;
|
||||
std::map<std::string, ISrsHttpHandler*>::iterator it;
|
||||
for (it = entry->streams.begin(); it != entry->streams.end(); ++it) {
|
||||
ISrsGoHttpHandler* stream = it->second;
|
||||
ISrsHttpHandler* stream = it->second;
|
||||
stream->entry->enabled = true;
|
||||
}
|
||||
|
||||
|
@ -891,33 +925,37 @@ int SrsHttpServer::mount_hls(SrsRequest* r)
|
|||
int SrsHttpServer::hls_update_m3u8(SrsRequest* r, string m3u8)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
std::string mount = m3u8;
|
||||
|
||||
// when no hls mounted, ignore.
|
||||
if (hls.find(r->vhost) == hls.end()) {
|
||||
return ret;
|
||||
}
|
||||
std::string sid = r->get_stream_url();
|
||||
SrsHlsEntry* entry = NULL;
|
||||
|
||||
SrsHlsEntry* entry = hls[r->vhost];
|
||||
srs_assert(entry);
|
||||
|
||||
std::string mount = entry->mount;
|
||||
|
||||
// replace the vhost variable
|
||||
mount = srs_string_replace(mount, "[vhost]", r->vhost);
|
||||
mount = srs_string_replace(mount, "[app]", r->app);
|
||||
mount = srs_string_replace(mount, "[stream]", r->stream);
|
||||
|
||||
// remove the default vhost mount
|
||||
mount = srs_string_replace(mount, SRS_CONSTS_RTMP_DEFAULT_VHOST"/", "/");
|
||||
|
||||
if (entry->streams.find(mount) == entry->streams.end()) {
|
||||
ISrsGoHttpHandler* he = new SrsHlsM3u8Stream();
|
||||
entry->streams[mount] = he;
|
||||
|
||||
if ((ret = mux.handle(mount, he)) != ERROR_SUCCESS) {
|
||||
srs_error("handle mount=%s failed. ret=%d", mount.c_str(), ret);
|
||||
// create stream from template when not found.
|
||||
if (shls.find(sid) == shls.end()) {
|
||||
if (thls.find(r->vhost) == thls.end()) {
|
||||
srs_info("ignore mount hls stream for disabled");
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsHlsEntry* tmpl = thls[r->vhost];
|
||||
|
||||
entry = new SrsHlsEntry();
|
||||
entry->mount = tmpl->mount;
|
||||
|
||||
shls[sid] = entry;
|
||||
|
||||
if (entry->streams.find(mount) == entry->streams.end()) {
|
||||
ISrsHttpHandler* he = new SrsHlsM3u8Stream();
|
||||
entry->streams[mount] = he;
|
||||
|
||||
if ((ret = mux.handle(mount, he)) != ERROR_SUCCESS) {
|
||||
srs_error("handle mount=%s failed. ret=%d", mount.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
entry = shls[sid];
|
||||
}
|
||||
|
||||
// update the m3u8 stream.
|
||||
|
@ -934,12 +972,14 @@ int SrsHttpServer::hls_update_ts(SrsRequest* r, string uri, string ts)
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
std::string sid = r->get_stream_url();
|
||||
|
||||
// when no hls mounted, ignore.
|
||||
if (hls.find(r->vhost) == hls.end()) {
|
||||
if (shls.find(sid) == shls.end()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsHlsEntry* entry = hls[r->vhost];
|
||||
SrsHlsEntry* entry = shls[sid];
|
||||
srs_assert(entry);
|
||||
|
||||
std::string mount = entry->mount;
|
||||
|
@ -962,7 +1002,7 @@ int SrsHttpServer::hls_update_ts(SrsRequest* r, string uri, string ts)
|
|||
mount += uri;
|
||||
|
||||
if (entry->streams.find(mount) == entry->streams.end()) {
|
||||
ISrsGoHttpHandler* he = new SrsHlsTsStream();
|
||||
ISrsHttpHandler* he = new SrsHlsTsStream();
|
||||
entry->streams[mount] = he;
|
||||
|
||||
if ((ret = mux.handle(mount, he)) != ERROR_SUCCESS) {
|
||||
|
@ -983,16 +1023,18 @@ int SrsHttpServer::hls_update_ts(SrsRequest* r, string uri, string ts)
|
|||
|
||||
void SrsHttpServer::unmount_hls(SrsRequest* r)
|
||||
{
|
||||
if (hls.find(r->vhost) == hls.end()) {
|
||||
std::string sid = r->get_stream_url();
|
||||
|
||||
if (shls.find(sid) == shls.end()) {
|
||||
srs_info("ignore unmount hls stream for disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
SrsHlsEntry* entry = hls[r->vhost];
|
||||
SrsHlsEntry* entry = shls[sid];
|
||||
|
||||
std::map<std::string, ISrsGoHttpHandler*>::iterator it;
|
||||
std::map<std::string, ISrsHttpHandler*>::iterator it;
|
||||
for (it = entry->streams.begin(); it != entry->streams.end(); ++it) {
|
||||
ISrsGoHttpHandler* stream = it->second;
|
||||
ISrsHttpHandler* stream = it->second;
|
||||
stream->entry->enabled = false;
|
||||
}
|
||||
}
|
||||
|
@ -1097,9 +1139,8 @@ int SrsHttpServer::initialize_flv_streaming()
|
|||
}
|
||||
|
||||
SrsLiveEntry* entry = new SrsLiveEntry();
|
||||
entry->vhost = vhost;
|
||||
entry->mount = _srs_config->get_vhost_http_remux_mount(vhost);
|
||||
flvs[vhost] = entry;
|
||||
tflvs[vhost] = entry;
|
||||
srs_trace("http flv live stream, vhost=%s, mount=%s",
|
||||
vhost.c_str(), entry->mount.c_str());
|
||||
}
|
||||
|
@ -1131,9 +1172,8 @@ int SrsHttpServer::initialize_hls_streaming()
|
|||
}
|
||||
|
||||
SrsHlsEntry* entry = new SrsHlsEntry();
|
||||
entry->vhost = vhost;
|
||||
entry->mount = _srs_config->get_hls_mount(vhost);
|
||||
hls[vhost] = entry;
|
||||
thls[vhost] = entry;
|
||||
srs_trace("http hls live stream, vhost=%s, mount=%s",
|
||||
vhost.c_str(), entry->mount.c_str());
|
||||
}
|
||||
|
@ -1153,7 +1193,7 @@ SrsHttpConn::~SrsHttpConn()
|
|||
srs_freep(parser);
|
||||
}
|
||||
|
||||
void SrsHttpConn::kbps_resample()
|
||||
void SrsHttpConn::resample()
|
||||
{
|
||||
// TODO: FIXME: implements it
|
||||
}
|
||||
|
@ -1170,6 +1210,11 @@ int64_t SrsHttpConn::get_recv_bytes_delta()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void SrsHttpConn::cleanup()
|
||||
{
|
||||
// TODO: FIXME: implements it
|
||||
}
|
||||
|
||||
int SrsHttpConn::do_cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
@ -1194,15 +1239,22 @@ int SrsHttpConn::do_cycle()
|
|||
return ret;
|
||||
}
|
||||
|
||||
// if SUCCESS, always NOT-NULL and completed message.
|
||||
// if SUCCESS, always NOT-NULL.
|
||||
srs_assert(req);
|
||||
srs_assert(req->is_complete());
|
||||
|
||||
// always free it in this scope.
|
||||
SrsAutoFree(SrsHttpMessage, req);
|
||||
|
||||
// TODO: FIXME: use the post body.
|
||||
std::string res;
|
||||
|
||||
// get response body.
|
||||
if ((ret = req->body_read_all(res)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ok, handle http request.
|
||||
SrsGoHttpResponseWriter writer(&skt);
|
||||
SrsHttpResponseWriter writer(&skt);
|
||||
if ((ret = process_request(&writer, req)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -1211,7 +1263,7 @@ int SrsHttpConn::do_cycle()
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsHttpConn::process_request(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsHttpConn::process_request(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
|
|
@ -59,14 +59,14 @@ class SrsSharedPtrMessage;
|
|||
* server will write flv header and sequence header,
|
||||
* then seek(10240) and response flv tag data.
|
||||
*/
|
||||
class SrsVodStream : public SrsGoHttpFileServer
|
||||
class SrsVodStream : public SrsHttpFileServer
|
||||
{
|
||||
public:
|
||||
SrsVodStream(std::string root_dir);
|
||||
virtual ~SrsVodStream();
|
||||
protected:
|
||||
virtual int serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset);
|
||||
virtual int serve_mp4_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int start, int end);
|
||||
virtual int serve_flv_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset);
|
||||
virtual int serve_mp4_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int start, int end);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -214,9 +214,9 @@ public:
|
|||
class SrsStreamWriter : public SrsFileWriter
|
||||
{
|
||||
private:
|
||||
ISrsGoHttpResponseWriter* writer;
|
||||
ISrsHttpResponseWriter* writer;
|
||||
public:
|
||||
SrsStreamWriter(ISrsGoHttpResponseWriter* w);
|
||||
SrsStreamWriter(ISrsHttpResponseWriter* w);
|
||||
virtual ~SrsStreamWriter();
|
||||
public:
|
||||
virtual int open(std::string file);
|
||||
|
@ -232,7 +232,7 @@ public:
|
|||
* the flv live stream supports access rtmp in flv over http.
|
||||
* srs will remux rtmp to flv streaming.
|
||||
*/
|
||||
class SrsLiveStream : public ISrsGoHttpHandler
|
||||
class SrsLiveStream : public ISrsHttpHandler
|
||||
{
|
||||
private:
|
||||
SrsRequest* req;
|
||||
|
@ -242,7 +242,7 @@ public:
|
|||
SrsLiveStream(SrsSource* s, SrsRequest* r, SrsStreamCache* c);
|
||||
virtual ~SrsLiveStream();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
private:
|
||||
virtual int streaming_send_messages(ISrsStreamEncoder* enc, SrsSharedPtrMessage** msgs, int nb_msgs);
|
||||
};
|
||||
|
@ -252,8 +252,10 @@ private:
|
|||
*/
|
||||
struct SrsLiveEntry
|
||||
{
|
||||
std::string vhost;
|
||||
// for template, the mount contains variables.
|
||||
// for concrete stream, the mount is url to access.
|
||||
std::string mount;
|
||||
|
||||
SrsLiveStream* stream;
|
||||
SrsStreamCache* cache;
|
||||
|
||||
|
@ -263,7 +265,7 @@ struct SrsLiveEntry
|
|||
/**
|
||||
* the m3u8 stream handler.
|
||||
*/
|
||||
class SrsHlsM3u8Stream : public ISrsGoHttpHandler
|
||||
class SrsHlsM3u8Stream : public ISrsHttpHandler
|
||||
{
|
||||
private:
|
||||
std::string m3u8;
|
||||
|
@ -273,13 +275,13 @@ public:
|
|||
public:
|
||||
virtual void set_m3u8(std::string v);
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
/**
|
||||
* the ts stream handler.
|
||||
*/
|
||||
class SrsHlsTsStream : public ISrsGoHttpHandler
|
||||
class SrsHlsTsStream : public ISrsHttpHandler
|
||||
{
|
||||
private:
|
||||
std::string ts;
|
||||
|
@ -289,7 +291,7 @@ public:
|
|||
public:
|
||||
virtual void set_ts(std::string v);
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -297,12 +299,13 @@ public:
|
|||
*/
|
||||
struct SrsHlsEntry
|
||||
{
|
||||
std::string vhost;
|
||||
// for template, the mount contains variables.
|
||||
// for concrete stream, the mount is url to access.
|
||||
std::string mount;
|
||||
|
||||
// key: the m3u8/ts file path.
|
||||
// value: the http handler.
|
||||
std::map<std::string, ISrsGoHttpHandler*> streams;
|
||||
std::map<std::string, ISrsHttpHandler*> streams;
|
||||
|
||||
SrsHlsEntry();
|
||||
};
|
||||
|
@ -314,11 +317,15 @@ struct SrsHlsEntry
|
|||
class SrsHttpServer : public ISrsReloadHandler
|
||||
{
|
||||
public:
|
||||
SrsGoHttpServeMux mux;
|
||||
// the flv live streaming template.
|
||||
std::map<std::string, SrsLiveEntry*> flvs;
|
||||
// the hls live streaming template.
|
||||
std::map<std::string, SrsHlsEntry*> hls;
|
||||
SrsHttpServeMux mux;
|
||||
// the flv live streaming template, to create streams.
|
||||
std::map<std::string, SrsLiveEntry*> tflvs;
|
||||
// the flv live streaming streams, crote by template.
|
||||
std::map<std::string, SrsLiveEntry*> sflvs;
|
||||
// the hls live streaming template, to create streams.
|
||||
std::map<std::string, SrsHlsEntry*> thls;
|
||||
// the hls live streaming streams, crote by template.
|
||||
std::map<std::string, SrsHlsEntry*> shls;
|
||||
public:
|
||||
SrsHttpServer();
|
||||
virtual ~SrsHttpServer();
|
||||
|
@ -353,16 +360,16 @@ private:
|
|||
public:
|
||||
SrsHttpConn(SrsServer* svr, st_netfd_t fd, SrsHttpServer* m);
|
||||
virtual ~SrsHttpConn();
|
||||
public:
|
||||
virtual void kbps_resample();
|
||||
// interface IKbpsDelta
|
||||
public:
|
||||
virtual void resample();
|
||||
virtual int64_t get_send_bytes_delta();
|
||||
virtual int64_t get_recv_bytes_delta();
|
||||
virtual void cleanup();
|
||||
protected:
|
||||
virtual int do_cycle();
|
||||
private:
|
||||
virtual int process_request(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int process_request(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -35,6 +35,7 @@ using namespace std;
|
|||
#include <srs_app_json.hpp>
|
||||
#include <srs_app_dvr.hpp>
|
||||
#include <srs_app_http_client.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
|
||||
#define SRS_HTTP_RESPONSE_OK __SRS_XSTR(ERROR_SUCCESS)
|
||||
|
||||
|
@ -53,13 +54,6 @@ int SrsHttpHooks::on_connect(string url, int client_id, string ip, SrsRequest* r
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
SrsHttpUri uri;
|
||||
if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
|
||||
srs_error("http uri parse on_connect url failed. "
|
||||
"client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_STR("action", "on_connect") << __SRS_JFIELD_CONT
|
||||
|
@ -70,31 +64,14 @@ int SrsHttpHooks::on_connect(string url, int client_id, string ip, SrsRequest* r
|
|||
<< __SRS_JFIELD_STR("tcUrl", req->tcUrl) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("pageUrl", req->pageUrl)
|
||||
<< __SRS_JOBJECT_END;
|
||||
|
||||
std::string data = ss.str();
|
||||
std::string res;
|
||||
int status_code;
|
||||
|
||||
SrsHttpClient http;
|
||||
if ((ret = http.post(&uri, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
if ((ret = do_post(url, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
srs_error("http post on_connect uri failed. "
|
||||
"client_id=%d, url=%s, request=%s, response=%s, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ensure the http status is ok.
|
||||
// https://github.com/winlinvip/simple-rtmp-server/issues/158
|
||||
if (status_code != SRS_CONSTS_HTTP_OK) {
|
||||
ret = ERROR_HTTP_STATUS_INVLIAD;
|
||||
srs_error("http hook on_connect status failed. "
|
||||
"client_id=%d, code=%d, ret=%d", client_id, status_code, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
|
||||
ret = ERROR_HTTP_DATA_INVLIAD;
|
||||
srs_error("http hook on_connect validate failed. "
|
||||
"client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
|
||||
"client_id=%d, url=%s, request=%s, response=%s, code=%d, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), status_code, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -109,13 +86,6 @@ void SrsHttpHooks::on_close(string url, int client_id, string ip, SrsRequest* re
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
SrsHttpUri uri;
|
||||
if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
|
||||
srs_warn("http uri parse on_close url failed, ignored. "
|
||||
"client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
|
||||
return;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_STR("action", "on_close") << __SRS_JFIELD_CONT
|
||||
|
@ -124,31 +94,14 @@ void SrsHttpHooks::on_close(string url, int client_id, string ip, SrsRequest* re
|
|||
<< __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("app", req->app)
|
||||
<< __SRS_JOBJECT_END;
|
||||
|
||||
std::string data = ss.str();
|
||||
std::string res;
|
||||
int status_code;
|
||||
|
||||
SrsHttpClient http;
|
||||
if ((ret = http.post(&uri, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
if ((ret = do_post(url, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
srs_warn("http post on_close uri failed, ignored. "
|
||||
"client_id=%d, url=%s, request=%s, response=%s, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), ret);
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure the http status is ok.
|
||||
// https://github.com/winlinvip/simple-rtmp-server/issues/158
|
||||
if (status_code != SRS_CONSTS_HTTP_OK) {
|
||||
ret = ERROR_HTTP_STATUS_INVLIAD;
|
||||
srs_error("http hook on_close status failed. "
|
||||
"client_id=%d, code=%d, ret=%d", client_id, status_code, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
|
||||
ret = ERROR_HTTP_DATA_INVLIAD;
|
||||
srs_warn("http hook on_close validate failed, ignored. "
|
||||
"client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
|
||||
"client_id=%d, url=%s, request=%s, response=%s, code=%d, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), status_code, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -163,13 +116,6 @@ int SrsHttpHooks::on_publish(string url, int client_id, string ip, SrsRequest* r
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
SrsHttpUri uri;
|
||||
if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
|
||||
srs_error("http uri parse on_publish url failed. "
|
||||
"client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_STR("action", "on_publish") << __SRS_JFIELD_CONT
|
||||
|
@ -179,31 +125,14 @@ int SrsHttpHooks::on_publish(string url, int client_id, string ip, SrsRequest* r
|
|||
<< __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("stream", req->stream)
|
||||
<< __SRS_JOBJECT_END;
|
||||
|
||||
std::string data = ss.str();
|
||||
std::string res;
|
||||
int status_code;
|
||||
|
||||
SrsHttpClient http;
|
||||
if ((ret = http.post(&uri, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
if ((ret = do_post(url, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
srs_error("http post on_publish uri failed. "
|
||||
"client_id=%d, url=%s, request=%s, response=%s, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ensure the http status is ok.
|
||||
// https://github.com/winlinvip/simple-rtmp-server/issues/158
|
||||
if (status_code != SRS_CONSTS_HTTP_OK) {
|
||||
ret = ERROR_HTTP_STATUS_INVLIAD;
|
||||
srs_error("http hook on_publish status failed. "
|
||||
"client_id=%d, code=%d, ret=%d", client_id, status_code, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
|
||||
ret = ERROR_HTTP_DATA_INVLIAD;
|
||||
srs_error("http hook on_publish validate failed. "
|
||||
"client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
|
||||
"client_id=%d, url=%s, request=%s, response=%s, code=%d, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), status_code, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -218,13 +147,6 @@ void SrsHttpHooks::on_unpublish(string url, int client_id, string ip, SrsRequest
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
SrsHttpUri uri;
|
||||
if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
|
||||
srs_warn("http uri parse on_unpublish url failed, ignored. "
|
||||
"client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
|
||||
return;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_STR("action", "on_unpublish") << __SRS_JFIELD_CONT
|
||||
|
@ -234,31 +156,14 @@ void SrsHttpHooks::on_unpublish(string url, int client_id, string ip, SrsRequest
|
|||
<< __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("stream", req->stream)
|
||||
<< __SRS_JOBJECT_END;
|
||||
|
||||
std::string data = ss.str();
|
||||
std::string res;
|
||||
int status_code;
|
||||
|
||||
SrsHttpClient http;
|
||||
if ((ret = http.post(&uri, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
if ((ret = do_post(url, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
srs_warn("http post on_unpublish uri failed, ignored. "
|
||||
"client_id=%d, url=%s, request=%s, response=%s, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), ret);
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure the http status is ok.
|
||||
// https://github.com/winlinvip/simple-rtmp-server/issues/158
|
||||
if (status_code != SRS_CONSTS_HTTP_OK) {
|
||||
ret = ERROR_HTTP_STATUS_INVLIAD;
|
||||
srs_error("http hook on_unpublish status failed. "
|
||||
"client_id=%d, code=%d, ret=%d", client_id, status_code, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
|
||||
ret = ERROR_HTTP_DATA_INVLIAD;
|
||||
srs_warn("http hook on_unpublish validate failed, ignored. "
|
||||
"client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
|
||||
"client_id=%d, url=%s, request=%s, response=%s, code=%d, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), status_code, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -273,13 +178,6 @@ int SrsHttpHooks::on_play(string url, int client_id, string ip, SrsRequest* req)
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
SrsHttpUri uri;
|
||||
if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
|
||||
srs_error("http uri parse on_play url failed. "
|
||||
"client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_STR("action", "on_play") << __SRS_JFIELD_CONT
|
||||
|
@ -289,31 +187,14 @@ int SrsHttpHooks::on_play(string url, int client_id, string ip, SrsRequest* req)
|
|||
<< __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("stream", req->stream)
|
||||
<< __SRS_JOBJECT_END;
|
||||
|
||||
std::string data = ss.str();
|
||||
std::string res;
|
||||
int status_code;
|
||||
|
||||
SrsHttpClient http;
|
||||
if ((ret = http.post(&uri, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
if ((ret = do_post(url, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
srs_error("http post on_play uri failed. "
|
||||
"client_id=%d, url=%s, request=%s, response=%s, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ensure the http status is ok.
|
||||
// https://github.com/winlinvip/simple-rtmp-server/issues/158
|
||||
if (status_code != SRS_CONSTS_HTTP_OK) {
|
||||
ret = ERROR_HTTP_STATUS_INVLIAD;
|
||||
srs_error("http hook on_play status failed. "
|
||||
"client_id=%d, code=%d, ret=%d", client_id, status_code, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
|
||||
ret = ERROR_HTTP_DATA_INVLIAD;
|
||||
srs_error("http hook on_play validate failed. "
|
||||
"client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
|
||||
"client_id=%d, url=%s, request=%s, response=%s, code=%d, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), status_code, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -328,13 +209,6 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
SrsHttpUri uri;
|
||||
if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
|
||||
srs_warn("http uri parse on_stop url failed, ignored. "
|
||||
"client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
|
||||
return;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_STR("action", "on_stop") << __SRS_JFIELD_CONT
|
||||
|
@ -344,31 +218,14 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req
|
|||
<< __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("stream", req->stream)
|
||||
<< __SRS_JOBJECT_END;
|
||||
|
||||
std::string data = ss.str();
|
||||
std::string res;
|
||||
int status_code;
|
||||
|
||||
SrsHttpClient http;
|
||||
if ((ret = http.post(&uri, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
if ((ret = do_post(url, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
srs_warn("http post on_stop uri failed, ignored. "
|
||||
"client_id=%d, url=%s, request=%s, response=%s, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), ret);
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure the http status is ok.
|
||||
// https://github.com/winlinvip/simple-rtmp-server/issues/158
|
||||
if (status_code != SRS_CONSTS_HTTP_OK) {
|
||||
ret = ERROR_HTTP_STATUS_INVLIAD;
|
||||
srs_error("http hook on_stop status failed. "
|
||||
"client_id=%d, code=%d, ret=%d", client_id, status_code, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
|
||||
ret = ERROR_HTTP_DATA_INVLIAD;
|
||||
srs_warn("http hook on_stop validate failed, ignored. "
|
||||
"client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
|
||||
"client_id=%d, url=%s, request=%s, response=%s, code=%d, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), status_code, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -383,13 +240,6 @@ int SrsHttpHooks::on_dvr(string url, int client_id, string ip, SrsRequest* req,
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
SrsHttpUri uri;
|
||||
if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
|
||||
srs_error("http uri parse on_dvr url failed, ignored. "
|
||||
"client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_STR("action", "on_dvr") << __SRS_JFIELD_CONT
|
||||
|
@ -401,31 +251,14 @@ int SrsHttpHooks::on_dvr(string url, int client_id, string ip, SrsRequest* req,
|
|||
<< __SRS_JFIELD_STR("cwd", cwd) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("file", file)
|
||||
<< __SRS_JOBJECT_END;
|
||||
|
||||
std::string data = ss.str();
|
||||
std::string res;
|
||||
int status_code;
|
||||
|
||||
SrsHttpClient http;
|
||||
if ((ret = http.post(&uri, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
if ((ret = do_post(url, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
srs_error("http post on_dvr uri failed, ignored. "
|
||||
"client_id=%d, url=%s, request=%s, response=%s, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ensure the http status is ok.
|
||||
// https://github.com/winlinvip/simple-rtmp-server/issues/158
|
||||
if (status_code != SRS_CONSTS_HTTP_OK) {
|
||||
ret = ERROR_HTTP_STATUS_INVLIAD;
|
||||
srs_error("http hook on_dvr status failed. "
|
||||
"client_id=%d, code=%d, ret=%d", client_id, status_code, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
|
||||
ret = ERROR_HTTP_DATA_INVLIAD;
|
||||
srs_warn("http hook on_dvr validate failed, ignored. "
|
||||
"client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
|
||||
"client_id=%d, url=%s, request=%s, response=%s, code=%d, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), status_code, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -440,13 +273,6 @@ int SrsHttpHooks::on_dvr_reap_segment(string url, int client_id, SrsRequest* req
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
SrsHttpUri uri;
|
||||
if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
|
||||
srs_error("http uri parse on_dvr_reap_segment url failed, ignored. "
|
||||
"client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_STR("action", "on_dvr_reap_segment") << __SRS_JFIELD_CONT
|
||||
|
@ -457,31 +283,14 @@ int SrsHttpHooks::on_dvr_reap_segment(string url, int client_id, SrsRequest* req
|
|||
<< __SRS_JFIELD_STR("cwd", cwd) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("file", file)
|
||||
<< __SRS_JOBJECT_END;
|
||||
|
||||
std::string data = ss.str();
|
||||
std::string res;
|
||||
int status_code;
|
||||
|
||||
SrsHttpClient http;
|
||||
if ((ret = http.post(&uri, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
if ((ret = do_post(url, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
srs_error("http post on_dvr_reap_segment uri failed, ignored. "
|
||||
"client_id=%d, url=%s, request=%s, response=%s, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ensure the http status is ok.
|
||||
// https://github.com/winlinvip/simple-rtmp-server/issues/158
|
||||
if (status_code != SRS_CONSTS_HTTP_OK) {
|
||||
ret = ERROR_HTTP_STATUS_INVLIAD;
|
||||
srs_error("http hook on_dvr_reap_segment status failed. "
|
||||
"client_id=%d, code=%d, ret=%d", client_id, status_code, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
|
||||
ret = ERROR_HTTP_DATA_INVLIAD;
|
||||
srs_warn("http hook on_dvr_reap_segment validate failed, ignored. "
|
||||
"client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
|
||||
"client_id=%d, url=%s, request=%s, response=%s, code=%d, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), status_code, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -492,4 +301,44 @@ int SrsHttpHooks::on_dvr_reap_segment(string url, int client_id, SrsRequest* req
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsHttpHooks::do_post(std::string url, std::string req, int& code, string& res)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
SrsHttpUri uri;
|
||||
if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
|
||||
srs_error("http: post failed. url=%s, ret=%d", url.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsHttpClient http;
|
||||
if ((ret = http.initialize(uri.get_host(), uri.get_port())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsHttpMessage* msg = NULL;
|
||||
if ((ret = http.post(uri.get_path(), req, &msg)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
SrsAutoFree(SrsHttpMessage, msg);
|
||||
|
||||
code = msg->status_code();
|
||||
if ((ret = msg->body_read_all(res)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ensure the http status is ok.
|
||||
// https://github.com/winlinvip/simple-rtmp-server/issues/158
|
||||
if (code != SRS_CONSTS_HTTP_OK) {
|
||||
return ERROR_HTTP_STATUS_INVLIAD;
|
||||
}
|
||||
|
||||
// TODO: FIXME: parse json.
|
||||
if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
|
||||
return ERROR_HTTP_DATA_INVLIAD;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -113,6 +113,8 @@ public:
|
|||
* @param file the file path, can be relative or absolute path.
|
||||
*/
|
||||
static int on_dvr_reap_segment(std::string url, int client_id, SrsRequest* req, std::string cwd, std::string file);
|
||||
private:
|
||||
static int do_post(std::string url, std::string req, int& code, std::string& res);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -217,6 +217,7 @@ that is:
|
|||
#define __SRS_JFIELD_STR(k, v) "\"" << k << "\":\"" << v << "\""
|
||||
#define __SRS_JFIELD_ORG(k, v) "\"" << k << "\":" << std::dec << v
|
||||
#define __SRS_JFIELD_BOOL(k, v) __SRS_JFIELD_ORG(k, (v? "true":"false"))
|
||||
#define __SRS_JFIELD_NULL(k) "\"" << k << "\":null"
|
||||
#define __SRS_JFIELD_ERROR(ret) "\"" << "code" << "\":" << ret
|
||||
#define __SRS_JFIELD_CONT ","
|
||||
#define __SRS_JOBJECT_END "}"
|
||||
|
|
|
@ -203,20 +203,29 @@ int64_t SrsKbps::get_recv_bytes()
|
|||
return is.get_total_bytes();
|
||||
}
|
||||
|
||||
void SrsKbps::resample()
|
||||
{
|
||||
sample();
|
||||
}
|
||||
|
||||
int64_t SrsKbps::get_send_bytes_delta()
|
||||
{
|
||||
int64_t delta = os.get_total_bytes() - os.delta_bytes;
|
||||
os.delta_bytes = os.get_total_bytes();
|
||||
return delta;
|
||||
}
|
||||
|
||||
int64_t SrsKbps::get_recv_bytes_delta()
|
||||
{
|
||||
int64_t delta = is.get_total_bytes() - is.delta_bytes;
|
||||
is.delta_bytes = is.get_total_bytes();
|
||||
return delta;
|
||||
}
|
||||
|
||||
void SrsKbps::cleanup()
|
||||
{
|
||||
os.delta_bytes = os.get_total_bytes();
|
||||
is.delta_bytes = is.get_total_bytes();
|
||||
}
|
||||
|
||||
void SrsKbps::add_delta(IKbpsDelta* delta)
|
||||
{
|
||||
srs_assert(delta);
|
||||
|
|
|
@ -107,6 +107,11 @@ public:
|
|||
|
||||
/**
|
||||
* the interface which provices delta of bytes.
|
||||
* for a delta, for example, a live stream connection, we can got the delta by:
|
||||
* IKbpsDelta* delta = ...;
|
||||
* delta->resample();
|
||||
* kbps->add_delta(delta);
|
||||
* delta->cleanup();
|
||||
*/
|
||||
class IKbpsDelta
|
||||
{
|
||||
|
@ -114,25 +119,41 @@ public:
|
|||
IKbpsDelta();
|
||||
virtual ~IKbpsDelta();
|
||||
public:
|
||||
/**
|
||||
* resample to generate the value of delta bytes.
|
||||
*/
|
||||
virtual void resample() = 0;
|
||||
/**
|
||||
* get the send or recv bytes delta.
|
||||
*/
|
||||
virtual int64_t get_send_bytes_delta() = 0;
|
||||
virtual int64_t get_recv_bytes_delta() = 0;
|
||||
/**
|
||||
* cleanup the value of delta bytes.
|
||||
*/
|
||||
virtual void cleanup() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* to statistic the kbps of io.
|
||||
* itself can be a statistic source, for example, used for SRS bytes stat.
|
||||
* there are two usage scenarios:
|
||||
* 1. connections to calc kbps:
|
||||
* set_io(in, out)
|
||||
* sample()
|
||||
* get_xxx_kbps().
|
||||
* 1. connections to calc kbps by sample():
|
||||
* SrsKbps* kbps = ...;
|
||||
* kbps->set_io(in, out)
|
||||
* kbps->sample()
|
||||
* kbps->get_xxx_kbps().
|
||||
* the connections know how many bytes already send/recv.
|
||||
* 2. server to calc kbps:
|
||||
* set_io(NULL, NULL)
|
||||
* 2. server to calc kbps by add_delta():
|
||||
* SrsKbps* kbps = ...;
|
||||
* kbps->set_io(NULL, NULL)
|
||||
* for each connection in connections:
|
||||
* add_delta(connections) // where connection is a IKbpsDelta*
|
||||
* sample()
|
||||
* get_xxx_kbps().
|
||||
* IKbpsDelta* delta = connection; // where connection implements IKbpsDelta
|
||||
* delta->resample()
|
||||
* kbps->add_delta(delta)
|
||||
* delta->cleanup()
|
||||
* kbps->sample()
|
||||
* kbps->get_xxx_kbps().
|
||||
* the server never know how many bytes already send/recv, for the connection maybe closed.
|
||||
*/
|
||||
class SrsKbps : public virtual ISrsProtocolStatistic, public virtual IKbpsDelta
|
||||
|
@ -174,18 +195,26 @@ public:
|
|||
*/
|
||||
virtual int64_t get_send_bytes();
|
||||
virtual int64_t get_recv_bytes();
|
||||
public:
|
||||
/**
|
||||
* resample to get the delta.
|
||||
*/
|
||||
virtual void resample();
|
||||
/**
|
||||
* get the delta of send/recv bytes.
|
||||
* @remark, used for add_delta to calc the total system bytes/kbps.
|
||||
*/
|
||||
virtual int64_t get_send_bytes_delta();
|
||||
virtual int64_t get_recv_bytes_delta();
|
||||
/**
|
||||
* cleanup the delta.
|
||||
*/
|
||||
virtual void cleanup();
|
||||
public:
|
||||
/**
|
||||
* add delta to kbps clac mechenism.
|
||||
* we donot know the total bytes, but know the delta, for instance,
|
||||
* for rtmp server to calc total bytes and kbps.
|
||||
* @remark user must invoke sample() when invoke this method.
|
||||
* @remark user must invoke sample() to calc result after invoke this method.
|
||||
* @param delta, assert should never be NULL.
|
||||
*/
|
||||
virtual void add_delta(IKbpsDelta* delta);
|
||||
|
|
|
@ -130,11 +130,13 @@ SrsMpegtsOverUdp::SrsMpegtsOverUdp(SrsConfDirective* c)
|
|||
context = new SrsTsContext();
|
||||
buffer = new SrsSimpleBuffer();
|
||||
output = _srs_config->get_stream_caster_output(c);
|
||||
|
||||
req = NULL;
|
||||
io = NULL;
|
||||
client = NULL;
|
||||
stfd = NULL;
|
||||
stream_id = 0;
|
||||
|
||||
avc = new SrsRawH264Stream();
|
||||
aac = new SrsRawAacStream();
|
||||
h264_sps_changed = false;
|
||||
|
@ -159,8 +161,6 @@ SrsMpegtsOverUdp::~SrsMpegtsOverUdp()
|
|||
|
||||
int SrsMpegtsOverUdp::on_udp_packet(sockaddr_in* from, char* buf, int nb_buf)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
std::string peer_ip = inet_ntoa(from->sin_addr);
|
||||
int peer_port = ntohs(from->sin_port);
|
||||
|
||||
|
@ -169,6 +169,13 @@ int SrsMpegtsOverUdp::on_udp_packet(sockaddr_in* from, char* buf, int nb_buf)
|
|||
|
||||
srs_info("udp: got %s:%d packet %d/%d bytes",
|
||||
peer_ip.c_str(), peer_port, nb_buf, buffer->length());
|
||||
|
||||
return on_udp_bytes(peer_ip, peer_port, buf, nb_buf);
|
||||
}
|
||||
|
||||
int SrsMpegtsOverUdp::on_udp_bytes(string host, int port, char* buf, int nb_buf)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// collect nMB data to parse in a time.
|
||||
// TODO: FIXME: comment the following for release.
|
||||
|
@ -215,8 +222,7 @@ int SrsMpegtsOverUdp::on_udp_packet(sockaddr_in* from, char* buf, int nb_buf)
|
|||
|
||||
// drop ts packet when size not modulus by 188
|
||||
if (buffer->length() < SRS_TS_PACKET_SIZE) {
|
||||
srs_warn("udp: wait %s:%d packet %d/%d bytes",
|
||||
peer_ip.c_str(), peer_port, nb_buf, buffer->length());
|
||||
srs_warn("udp: wait %s:%d packet %d/%d bytes", host.c_str(), port, nb_buf, buffer->length());
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -582,6 +588,7 @@ int SrsMpegtsOverUdp::connect()
|
|||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// when ok, ignore.
|
||||
// TODO: FIXME: should reconnect when disconnected.
|
||||
if (io || client) {
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -109,6 +109,8 @@ public:
|
|||
// interface ISrsUdpHandler
|
||||
public:
|
||||
virtual int on_udp_packet(sockaddr_in* from, char* buf, int nb_buf);
|
||||
private:
|
||||
virtual int on_udp_bytes(std::string host, int port, char* buf, int nb_buf);
|
||||
// interface ISrsTsHandler
|
||||
public:
|
||||
virtual int on_ts_message(SrsTsMessage* msg);
|
||||
|
|
|
@ -27,6 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -109,11 +110,6 @@ SrsRtmpConn::~SrsRtmpConn()
|
|||
srs_freep(kbps);
|
||||
}
|
||||
|
||||
void SrsRtmpConn::kbps_resample()
|
||||
{
|
||||
kbps->sample();
|
||||
}
|
||||
|
||||
// TODO: return detail message when error for client.
|
||||
int SrsRtmpConn::do_cycle()
|
||||
{
|
||||
|
@ -201,7 +197,7 @@ int SrsRtmpConn::do_cycle()
|
|||
ret = service_cycle();
|
||||
http_hooks_on_close();
|
||||
SrsStatistic* stat = SrsStatistic::instance();
|
||||
stat->on_close(_srs_context->get_id());
|
||||
stat->on_disconnect(_srs_context->get_id());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -254,6 +250,11 @@ int SrsRtmpConn::on_reload_vhost_realtime(string vhost)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void SrsRtmpConn::resample()
|
||||
{
|
||||
kbps->resample();
|
||||
}
|
||||
|
||||
int64_t SrsRtmpConn::get_send_bytes_delta()
|
||||
{
|
||||
return kbps->get_send_bytes_delta();
|
||||
|
@ -263,6 +264,11 @@ int64_t SrsRtmpConn::get_recv_bytes_delta()
|
|||
{
|
||||
return kbps->get_recv_bytes_delta();
|
||||
}
|
||||
|
||||
void SrsRtmpConn::cleanup()
|
||||
{
|
||||
kbps->cleanup();
|
||||
}
|
||||
|
||||
int SrsRtmpConn::service_cycle()
|
||||
{
|
||||
|
@ -392,9 +398,11 @@ int SrsRtmpConn::stream_service_cycle()
|
|||
bool vhost_is_edge = _srs_config->get_vhost_is_edge(req->vhost);
|
||||
|
||||
// find a source to serve.
|
||||
SrsSource* source = NULL;
|
||||
if ((ret = SrsSource::find(req, server, server, &source)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
SrsSource* source = SrsSource::fetch(req);
|
||||
if (!source) {
|
||||
if ((ret = SrsSource::create(req, server, server, &source)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
srs_assert(source != NULL);
|
||||
|
||||
|
@ -622,6 +630,9 @@ int SrsRtmpConn::do_playing(SrsSource* source, SrsConsumer* consumer, SrsQueueRe
|
|||
mw_enabled = true;
|
||||
change_mw_sleep(_srs_config->get_mw_sleep_ms(req->vhost));
|
||||
|
||||
// set the sock options.
|
||||
play_set_sock_options();
|
||||
|
||||
while (true) {
|
||||
// collect elapse for pithy print.
|
||||
pprint->elapse();
|
||||
|
@ -1087,7 +1098,7 @@ void SrsRtmpConn::change_mw_sleep(int sleep_ms)
|
|||
socklen_t sock_buf_size = sizeof(int);
|
||||
getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &onb_sbuf, &sock_buf_size);
|
||||
|
||||
#ifdef SRS_PERF_MW_SO_SNDBUF
|
||||
#ifdef SRS_PERF_MW_SO_SNDBUF
|
||||
// the bytes:
|
||||
// 4KB=4096, 8KB=8192, 16KB=16384, 32KB=32768, 64KB=65536,
|
||||
// 128KB=131072, 256KB=262144, 512KB=524288
|
||||
|
@ -1104,6 +1115,11 @@ void SrsRtmpConn::change_mw_sleep(int sleep_ms)
|
|||
// socket send buffer, system will double it.
|
||||
int nb_sbuf = socket_buffer_size / 2;
|
||||
|
||||
// override the send buffer by macro.
|
||||
#ifdef SRS_PERF_SO_SNDBUF_SIZE
|
||||
nb_sbuf = SRS_PERF_SO_SNDBUF_SIZE / 2;
|
||||
#endif
|
||||
|
||||
// set the socket send buffer when required larger buffer
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &nb_sbuf, sock_buf_size) < 0) {
|
||||
srs_warn("set sock SO_SENDBUF=%d failed.", nb_sbuf);
|
||||
|
@ -1121,6 +1137,29 @@ void SrsRtmpConn::change_mw_sleep(int sleep_ms)
|
|||
mw_sleep = sleep_ms;
|
||||
}
|
||||
|
||||
void SrsRtmpConn::play_set_sock_options()
|
||||
{
|
||||
#ifdef SRS_PERF_TCP_NODELAY
|
||||
if (true) {
|
||||
int fd = st_netfd_fileno(stfd);
|
||||
|
||||
socklen_t nb_v = sizeof(int);
|
||||
|
||||
int ov = 0;
|
||||
getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &ov, &nb_v);
|
||||
|
||||
int v = 1;
|
||||
// set the socket send buffer when required larger buffer
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, nb_v) < 0) {
|
||||
srs_warn("set sock TCP_NODELAY=%d failed.", v);
|
||||
}
|
||||
getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, &nb_v);
|
||||
|
||||
srs_trace("set TCP_NODELAY %d=>%d", ov, v);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int SrsRtmpConn::check_edge_token_traverse_auth()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
|
|
@ -83,8 +83,6 @@ private:
|
|||
public:
|
||||
SrsRtmpConn(SrsServer* srs_server, st_netfd_t client_stfd);
|
||||
virtual ~SrsRtmpConn();
|
||||
public:
|
||||
virtual void kbps_resample();
|
||||
protected:
|
||||
virtual int do_cycle();
|
||||
// interface ISrsReloadHandler
|
||||
|
@ -94,8 +92,10 @@ public:
|
|||
virtual int on_reload_vhost_realtime(std::string vhost);
|
||||
// interface IKbpsDelta
|
||||
public:
|
||||
virtual void resample();
|
||||
virtual int64_t get_send_bytes_delta();
|
||||
virtual int64_t get_recv_bytes_delta();
|
||||
virtual void cleanup();
|
||||
private:
|
||||
// when valid and connected to vhost/app, service the client.
|
||||
virtual int service_cycle();
|
||||
|
@ -111,6 +111,7 @@ private:
|
|||
virtual int process_publish_message(SrsSource* source, SrsCommonMessage* msg, bool vhost_is_edge);
|
||||
virtual int process_play_control_msg(SrsConsumer* consumer, SrsCommonMessage* msg);
|
||||
virtual void change_mw_sleep(int sleep_ms);
|
||||
virtual void play_set_sock_options();
|
||||
private:
|
||||
virtual int check_edge_token_traverse_auth();
|
||||
virtual int connect_server(int origin_index, st_netfd_t* pstsock);
|
||||
|
|
|
@ -131,7 +131,7 @@ int SrsRtpConn::on_udp_packet(sockaddr_in* from, char* buf, int nb_buf)
|
|||
|
||||
SrsRtspAudioCache::SrsRtspAudioCache()
|
||||
{
|
||||
dts = NULL;
|
||||
dts = 0;
|
||||
audio_samples = NULL;
|
||||
payload = NULL;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ using namespace std;
|
|||
#include <srs_app_heartbeat.hpp>
|
||||
#include <srs_app_mpegts_udp.hpp>
|
||||
#include <srs_app_rtsp.hpp>
|
||||
#include <srs_app_statistic.hpp>
|
||||
|
||||
// signal defines.
|
||||
#define SIGNAL_RELOAD SIGHUP
|
||||
|
@ -392,13 +393,12 @@ SrsServer::SrsServer()
|
|||
pid_fd = -1;
|
||||
|
||||
signal_manager = NULL;
|
||||
kbps = NULL;
|
||||
|
||||
// donot new object in constructor,
|
||||
// for some global instance is not ready now,
|
||||
// new these objects in initialize instead.
|
||||
#ifdef SRS_AUTO_HTTP_API
|
||||
http_api_mux = new SrsGoHttpServeMux();
|
||||
http_api_mux = new SrsHttpServeMux();
|
||||
#endif
|
||||
#ifdef SRS_AUTO_HTTP_SERVER
|
||||
http_stream_mux = new SrsHttpServer();
|
||||
|
@ -452,7 +452,6 @@ void SrsServer::destroy()
|
|||
}
|
||||
|
||||
srs_freep(signal_manager);
|
||||
srs_freep(kbps);
|
||||
|
||||
// @remark never destroy the connections,
|
||||
// for it's still alive.
|
||||
|
@ -478,61 +477,11 @@ int SrsServer::initialize()
|
|||
srs_assert(!signal_manager);
|
||||
signal_manager = new SrsSignalManager(this);
|
||||
|
||||
srs_assert(!kbps);
|
||||
kbps = new SrsKbps();
|
||||
kbps->set_io(NULL, NULL);
|
||||
|
||||
#ifdef SRS_AUTO_HTTP_API
|
||||
if ((ret = http_api_mux->initialize()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SRS_AUTO_HTTP_API
|
||||
srs_assert(http_api_mux);
|
||||
if ((ret = http_api_mux->handle("/", new SrsGoApiRoot())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api", new SrsGoApiApi())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1", new SrsGoApiV1())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/versions", new SrsGoApiVersion())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/summaries", new SrsGoApiSummaries())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/rusages", new SrsGoApiRusages())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/self_proc_stats", new SrsGoApiSelfProcStats())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/system_proc_stats", new SrsGoApiSystemProcStats())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/meminfos", new SrsGoApiMemInfos())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/authors", new SrsGoApiAuthors())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/requests", new SrsGoApiRequests())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/vhosts", new SrsGoApiVhosts())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/streams", new SrsGoApiStreams())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/dvrs", new SrsGoApiDvrs())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SRS_AUTO_HTTP_SERVER
|
||||
srs_assert(http_stream_mux);
|
||||
|
@ -692,6 +641,56 @@ int SrsServer::register_signal()
|
|||
return signal_manager->start();
|
||||
}
|
||||
|
||||
int SrsServer::http_handle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
#ifdef SRS_AUTO_HTTP_API
|
||||
srs_assert(http_api_mux);
|
||||
if ((ret = http_api_mux->handle("/", new SrsGoApiRoot())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api", new SrsGoApiApi())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1", new SrsGoApiV1())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/versions", new SrsGoApiVersion())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/summaries", new SrsGoApiSummaries())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/rusages", new SrsGoApiRusages())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/self_proc_stats", new SrsGoApiSelfProcStats())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/system_proc_stats", new SrsGoApiSystemProcStats())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/meminfos", new SrsGoApiMemInfos())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/authors", new SrsGoApiAuthors())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/requests", new SrsGoApiRequests())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/vhosts", new SrsGoApiVhosts())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/streams", new SrsGoApiStreams())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsServer::ingest()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
@ -741,8 +740,8 @@ void SrsServer::remove(SrsConnection* conn)
|
|||
|
||||
srs_info("conn removed. conns=%d", (int)conns.size());
|
||||
|
||||
// resample the resource of specified connection.
|
||||
resample_kbps(conn);
|
||||
SrsStatistic* stat = SrsStatistic::instance();
|
||||
stat->kbps_add_delta(conn);
|
||||
|
||||
// all connections are created by server,
|
||||
// so we free it here.
|
||||
|
@ -858,9 +857,8 @@ int SrsServer::do_cycle()
|
|||
srs_update_network_devices();
|
||||
}
|
||||
if ((i % SRS_SYS_NETWORK_RTMP_SERVER_RESOLUTION_TIMES) == 0) {
|
||||
srs_info("update network rtmp server info.");
|
||||
resample_kbps(NULL);
|
||||
srs_update_rtmp_server((int)conns.size(), kbps);
|
||||
srs_info("update network server kbps info.");
|
||||
resample_kbps();
|
||||
}
|
||||
#ifdef SRS_AUTO_HTTP_PARSER
|
||||
if (_srs_config->get_heartbeat_enabled()) {
|
||||
|
@ -1009,31 +1007,25 @@ void SrsServer::close_listeners(SrsListenerType type)
|
|||
}
|
||||
}
|
||||
|
||||
void SrsServer::resample_kbps(SrsConnection* conn, bool do_resample)
|
||||
void SrsServer::resample_kbps()
|
||||
{
|
||||
// resample all when conn is NULL.
|
||||
if (!conn) {
|
||||
for (std::vector<SrsConnection*>::iterator it = conns.begin(); it != conns.end(); ++it) {
|
||||
SrsConnection* client = *it;
|
||||
srs_assert(client);
|
||||
|
||||
// only resample, do resample when all finished.
|
||||
resample_kbps(client, false);
|
||||
}
|
||||
SrsStatistic* stat = SrsStatistic::instance();
|
||||
|
||||
// collect delta from all clients.
|
||||
for (std::vector<SrsConnection*>::iterator it = conns.begin(); it != conns.end(); ++it) {
|
||||
SrsConnection* conn = *it;
|
||||
|
||||
kbps->sample();
|
||||
return;
|
||||
// add delta of connection to server kbps.,
|
||||
// for next sample() of server kbps can get the stat.
|
||||
stat->kbps_add_delta(conn);
|
||||
}
|
||||
|
||||
// resample for connection.
|
||||
conn->kbps_resample();
|
||||
// TODO: FXME: support all other connections.
|
||||
|
||||
// sample the kbps, get the stat.
|
||||
SrsKbps* kbps = stat->kbps_sample();
|
||||
|
||||
kbps->add_delta(conn);
|
||||
|
||||
// resample for server.
|
||||
if (do_resample) {
|
||||
kbps->sample();
|
||||
}
|
||||
srs_update_rtmp_server((int)conns.size(), kbps);
|
||||
}
|
||||
|
||||
int SrsServer::accept_client(SrsListenerType type, st_netfd_t client_stfd)
|
||||
|
|
|
@ -41,7 +41,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
class SrsServer;
|
||||
class SrsConnection;
|
||||
class SrsGoHttpServeMux;
|
||||
class SrsHttpServeMux;
|
||||
class SrsHttpServer;
|
||||
class SrsIngester;
|
||||
class SrsHttpHeartbeat;
|
||||
|
@ -178,7 +178,7 @@ class SrsServer : virtual public ISrsReloadHandler
|
|||
{
|
||||
private:
|
||||
#ifdef SRS_AUTO_HTTP_API
|
||||
SrsGoHttpServeMux* http_api_mux;
|
||||
SrsHttpServeMux* http_api_mux;
|
||||
#endif
|
||||
#ifdef SRS_AUTO_HTTP_SERVER
|
||||
SrsHttpServer* http_stream_mux;
|
||||
|
@ -210,10 +210,6 @@ private:
|
|||
*/
|
||||
SrsSignalManager* signal_manager;
|
||||
/**
|
||||
* server total kbps.
|
||||
*/
|
||||
SrsKbps* kbps;
|
||||
/**
|
||||
* user send the signal, convert to variable.
|
||||
*/
|
||||
bool signal_reload;
|
||||
|
@ -236,6 +232,7 @@ public:
|
|||
virtual int initialize_st();
|
||||
virtual int listen();
|
||||
virtual int register_signal();
|
||||
virtual int http_handle();
|
||||
virtual int ingest();
|
||||
virtual int cycle();
|
||||
// server utility
|
||||
|
@ -277,12 +274,9 @@ private:
|
|||
*/
|
||||
virtual void close_listeners(SrsListenerType type);
|
||||
/**
|
||||
* resample the server kbps.
|
||||
* if conn is NULL, resample all connections delta, then calc the total kbps.
|
||||
* @param conn, the connection to do resample the kbps. NULL to resample all connections.
|
||||
* @param do_resample, whether resample the server kbps. always false when sample a connection.
|
||||
* resample the server kbs.
|
||||
*/
|
||||
virtual void resample_kbps(SrsConnection* conn, bool do_resample = true);
|
||||
virtual void resample_kbps();
|
||||
// internal only
|
||||
public:
|
||||
/**
|
||||
|
@ -316,3 +310,4 @@ public:
|
|||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ using namespace std;
|
|||
#include <srs_kernel_codec.hpp>
|
||||
#include <srs_rtmp_msg_array.hpp>
|
||||
#include <srs_app_hds.hpp>
|
||||
#include <srs_app_statistic.hpp>
|
||||
|
||||
#define CONST_MAX_JITTER_MS 500
|
||||
#define DEFAULT_FRAME_TIME_MS 40
|
||||
|
@ -714,35 +715,47 @@ ISrsSourceHandler::~ISrsSourceHandler()
|
|||
|
||||
std::map<std::string, SrsSource*> SrsSource::pool;
|
||||
|
||||
int SrsSource::find(SrsRequest* r, ISrsSourceHandler* h, ISrsHlsHandler* hh, SrsSource** pps)
|
||||
int SrsSource::create(SrsRequest* r, ISrsSourceHandler* h, ISrsHlsHandler* hh, SrsSource** pps)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
string stream_url = r->get_stream_url();
|
||||
string vhost = r->vhost;
|
||||
|
||||
if (pool.find(stream_url) == pool.end()) {
|
||||
SrsSource* source = new SrsSource(hh);
|
||||
if ((ret = source->initialize(r, h)) != ERROR_SUCCESS) {
|
||||
srs_freep(source);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pool[stream_url] = source;
|
||||
srs_info("create new source for url=%s, vhost=%s",
|
||||
stream_url.c_str(), vhost.c_str());
|
||||
// should always not exists for create a source.
|
||||
srs_assert (pool.find(stream_url) == pool.end());
|
||||
|
||||
SrsSource* source = new SrsSource();
|
||||
if ((ret = source->initialize(r, h, hh)) != ERROR_SUCCESS) {
|
||||
srs_freep(source);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pool[stream_url] = source;
|
||||
srs_info("create new source for url=%s, vhost=%s", stream_url.c_str(), vhost.c_str());
|
||||
|
||||
*pps = source;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsSource* SrsSource::fetch(SrsRequest* r)
|
||||
{
|
||||
SrsSource* source = NULL;
|
||||
|
||||
string stream_url = r->get_stream_url();
|
||||
if (pool.find(stream_url) == pool.end()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
source = pool[stream_url];
|
||||
|
||||
// we always update the request of resource,
|
||||
// for origin auth is on, the token in request maybe invalid,
|
||||
// and we only need to update the token of request, it's simple.
|
||||
if (true) {
|
||||
SrsSource* source = pool[stream_url];
|
||||
source->_req->update_auth(r);
|
||||
*pps = source;
|
||||
}
|
||||
|
||||
return ret;
|
||||
source->_req->update_auth(r);
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
void SrsSource::destroy()
|
||||
|
@ -755,17 +768,16 @@ void SrsSource::destroy()
|
|||
pool.clear();
|
||||
}
|
||||
|
||||
SrsSource::SrsSource(ISrsHlsHandler* hh)
|
||||
SrsSource::SrsSource()
|
||||
{
|
||||
_req = NULL;
|
||||
jitter_algorithm = SrsRtmpJitterAlgorithmOFF;
|
||||
|
||||
#ifdef SRS_AUTO_HLS
|
||||
// TODO: FIXME: refine code, use subscriber pattern.
|
||||
hls = new SrsHls(this, hh);
|
||||
hls = new SrsHls();
|
||||
#endif
|
||||
#ifdef SRS_AUTO_DVR
|
||||
dvr = new SrsDvr(this);
|
||||
dvr = new SrsDvr();
|
||||
#endif
|
||||
#ifdef SRS_AUTO_TRANSCODE
|
||||
encoder = new SrsEncoder();
|
||||
|
@ -827,16 +839,26 @@ SrsSource::~SrsSource()
|
|||
srs_freep(_req);
|
||||
}
|
||||
|
||||
int SrsSource::initialize(SrsRequest* r, ISrsSourceHandler* h)
|
||||
int SrsSource::initialize(SrsRequest* r, ISrsSourceHandler* h, ISrsHlsHandler* hh)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
srs_assert(h);
|
||||
srs_assert(hh);
|
||||
srs_assert(!_req);
|
||||
|
||||
handler = h;
|
||||
_req = r->copy();
|
||||
atc = _srs_config->get_atc(_req->vhost);
|
||||
|
||||
#ifdef SRS_AUTO_HLS
|
||||
if ((ret = hls->initialize(this, hh)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SRS_AUTO_DVR
|
||||
if ((ret = dvr->initialize(_req)) != ERROR_SUCCESS) {
|
||||
if ((ret = dvr->initialize(this, _req)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
@ -1000,7 +1022,7 @@ int SrsSource::on_reload_vhost_dvr(string vhost)
|
|||
dvr->on_unpublish();
|
||||
|
||||
// reinitialize the dvr, update plan.
|
||||
if ((ret = dvr->initialize(_req)) != ERROR_SUCCESS) {
|
||||
if ((ret = dvr->initialize(this, _req)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1364,6 +1386,7 @@ int SrsSource::on_audio(SrsCommonMessage* __audio)
|
|||
|
||||
// cache the sequence header of aac, or first packet of mp3.
|
||||
// for example, the mp3 is used for hls to write the "right" audio codec.
|
||||
// TODO: FIXME: to refine the stream info system.
|
||||
bool is_aac_sequence_header = SrsFlvCodec::audio_is_sequence_header(msg.payload, msg.size);
|
||||
if (is_aac_sequence_header || !cache_sh_audio) {
|
||||
srs_freep(cache_sh_audio);
|
||||
|
@ -1383,11 +1406,18 @@ int SrsSource::on_audio(SrsCommonMessage* __audio)
|
|||
|
||||
static int flv_sample_sizes[] = {8, 16, 0};
|
||||
static int flv_sound_types[] = {1, 2, 0};
|
||||
|
||||
// when got audio stream info.
|
||||
SrsStatistic* stat = SrsStatistic::instance();
|
||||
if ((ret = stat->on_audio_info(_req, SrsCodecAudioAAC, sample.sound_rate, sample.sound_type, codec.aac_object)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
srs_trace("%dB audio sh, "
|
||||
"codec(%d, profile=%d, %dchannels, %dkbps, %dHZ), "
|
||||
"codec(%d, profile=%s, %dchannels, %dkbps, %dHZ), "
|
||||
"flv(%dbits, %dchannels, %dHZ)",
|
||||
msg.size, codec.audio_codec_id,
|
||||
codec.aac_profile, codec.aac_channels,
|
||||
srs_codec_aac_object2str(codec.aac_object).c_str(), codec.aac_channels,
|
||||
codec.audio_data_rate / 1000, aac_sample_rates[codec.aac_sample_rate],
|
||||
flv_sample_sizes[sample.sound_size], flv_sound_types[sample.sound_type],
|
||||
flv_sample_rates[sample.sound_rate]);
|
||||
|
@ -1515,10 +1545,17 @@ int SrsSource::on_video(SrsCommonMessage* __video)
|
|||
return ret;
|
||||
}
|
||||
|
||||
// when got video stream info.
|
||||
SrsStatistic* stat = SrsStatistic::instance();
|
||||
if ((ret = stat->on_video_info(_req, SrsCodecVideoAVC, codec.avc_profile, codec.avc_level)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
srs_trace("%dB video sh, "
|
||||
"codec(%d, profile=%d, level=%d, %dx%d, %dkbps, %dfps, %ds)",
|
||||
"codec(%d, profile=%s, level=%s, %dx%d, %dkbps, %dfps, %ds)",
|
||||
msg.size, codec.video_codec_id,
|
||||
codec.avc_profile, codec.avc_level, codec.width, codec.height,
|
||||
srs_codec_avc_profile2str(codec.avc_profile).c_str(),
|
||||
srs_codec_avc_level2str(codec.avc_level).c_str(), codec.width, codec.height,
|
||||
codec.video_data_rate / 1000, codec.frame_rate, codec.duration);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -381,7 +381,12 @@ public:
|
|||
* @param hh the event handler for hls.
|
||||
* @param pps the matched source, if success never be NULL.
|
||||
*/
|
||||
static int find(SrsRequest* r, ISrsSourceHandler* h, ISrsHlsHandler* hh, SrsSource** pps);
|
||||
static int create(SrsRequest* r, ISrsSourceHandler* h, ISrsHlsHandler* hh, SrsSource** pps);
|
||||
/**
|
||||
* get the exists source, NULL when not exists.
|
||||
* update the request and return the exists source.
|
||||
*/
|
||||
static SrsSource* fetch(SrsRequest* r);
|
||||
/**
|
||||
* when system exit, destroy the sources,
|
||||
* for gmc to analysis mem leaks.
|
||||
|
@ -451,15 +456,14 @@ private:
|
|||
// the cached audio sequence header.
|
||||
SrsSharedPtrMessage* cache_sh_audio;
|
||||
public:
|
||||
/**
|
||||
* @param _req the client request object,
|
||||
* this object will deep copy it for reload.
|
||||
*/
|
||||
SrsSource(ISrsHlsHandler* hh);
|
||||
SrsSource();
|
||||
virtual ~SrsSource();
|
||||
// initialize, get and setter.
|
||||
public:
|
||||
virtual int initialize(SrsRequest* r, ISrsSourceHandler* h);
|
||||
/**
|
||||
* initialize the hls with handlers.
|
||||
*/
|
||||
virtual int initialize(SrsRequest* r, ISrsSourceHandler* h, ISrsHlsHandler* hh);
|
||||
// interface ISrsReloadHandler
|
||||
public:
|
||||
virtual int on_reload_vhost_atc(std::string vhost);
|
||||
|
|
|
@ -26,6 +26,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_kernel_log.hpp>
|
||||
|
||||
#ifndef SRS_OSX
|
||||
#include <sys/epoll.h>
|
||||
bool srs_st_epoll_is_supported(void)
|
||||
{
|
||||
|
@ -38,11 +39,13 @@ bool srs_st_epoll_is_supported(void)
|
|||
|
||||
return (errno != ENOSYS);
|
||||
}
|
||||
#endif
|
||||
|
||||
int srs_init_st()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
#ifndef SRS_OSX
|
||||
// check epoll, some old linux donot support epoll.
|
||||
// @see https://github.com/winlinvip/simple-rtmp-server/issues/162
|
||||
if (!srs_st_epoll_is_supported()) {
|
||||
|
@ -58,6 +61,7 @@ int srs_init_st()
|
|||
return ret;
|
||||
}
|
||||
srs_verbose("st_set_eventsys use linux epoll success");
|
||||
#endif
|
||||
|
||||
if(st_init() != 0){
|
||||
ret = ERROR_ST_INITIALIZE;
|
||||
|
|
|
@ -29,6 +29,8 @@ using namespace std;
|
|||
|
||||
#include <srs_rtmp_sdk.hpp>
|
||||
#include <srs_app_json.hpp>
|
||||
#include <srs_app_kbps.hpp>
|
||||
#include <srs_app_conn.hpp>
|
||||
|
||||
int64_t __srs_gvid = getpid();
|
||||
|
||||
|
@ -40,20 +42,45 @@ int64_t __srs_generate_id()
|
|||
SrsStatisticVhost::SrsStatisticVhost()
|
||||
{
|
||||
id = __srs_generate_id();
|
||||
|
||||
kbps = new SrsKbps();
|
||||
kbps->set_io(NULL, NULL);
|
||||
}
|
||||
|
||||
SrsStatisticVhost::~SrsStatisticVhost()
|
||||
{
|
||||
srs_freep(kbps);
|
||||
}
|
||||
|
||||
SrsStatisticStream::SrsStatisticStream()
|
||||
{
|
||||
id = __srs_generate_id();
|
||||
vhost = NULL;
|
||||
|
||||
has_video = false;
|
||||
vcodec = SrsCodecVideoReserved;
|
||||
avc_profile = SrsAvcProfileReserved;
|
||||
avc_level = SrsAvcLevelReserved;
|
||||
|
||||
has_audio = false;
|
||||
acodec = SrsCodecAudioReserved1;
|
||||
asample_rate = SrsCodecAudioSampleRateReserved;
|
||||
asound_type = SrsCodecAudioSoundTypeReserved;
|
||||
aac_object = SrsAacObjectTypeReserved;
|
||||
|
||||
kbps = new SrsKbps();
|
||||
kbps->set_io(NULL, NULL);
|
||||
}
|
||||
|
||||
SrsStatisticStream::~SrsStatisticStream()
|
||||
{
|
||||
srs_freep(kbps);
|
||||
}
|
||||
|
||||
void SrsStatisticStream::close()
|
||||
{
|
||||
has_video = false;
|
||||
has_audio = false;
|
||||
}
|
||||
|
||||
SrsStatistic* SrsStatistic::_instance = new SrsStatistic();
|
||||
|
@ -61,10 +88,15 @@ SrsStatistic* SrsStatistic::_instance = new SrsStatistic();
|
|||
SrsStatistic::SrsStatistic()
|
||||
{
|
||||
_server_id = __srs_generate_id();
|
||||
|
||||
kbps = new SrsKbps();
|
||||
kbps->set_io(NULL, NULL);
|
||||
}
|
||||
|
||||
SrsStatistic::~SrsStatistic()
|
||||
{
|
||||
srs_freep(kbps);
|
||||
|
||||
if (true) {
|
||||
std::map<std::string, SrsStatisticVhost*>::iterator it;
|
||||
for (it = vhosts.begin(); it != vhosts.end(); it++) {
|
||||
|
@ -93,34 +125,54 @@ SrsStatistic* SrsStatistic::instance()
|
|||
return _instance;
|
||||
}
|
||||
|
||||
int SrsStatistic::on_video_info(SrsRequest* req,
|
||||
SrsCodecVideo vcodec, SrsAvcProfile avc_profile, SrsAvcLevel avc_level
|
||||
) {
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
SrsStatisticVhost* vhost = create_vhost(req);
|
||||
SrsStatisticStream* stream = create_stream(vhost, req);
|
||||
|
||||
stream->has_video = true;
|
||||
stream->vcodec = vcodec;
|
||||
stream->avc_profile = avc_profile;
|
||||
stream->avc_level = avc_level;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsStatistic::on_audio_info(SrsRequest* req,
|
||||
SrsCodecAudio acodec, SrsCodecAudioSampleRate asample_rate, SrsCodecAudioSoundType asound_type,
|
||||
SrsAacObjectType aac_object
|
||||
) {
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
SrsStatisticVhost* vhost = create_vhost(req);
|
||||
SrsStatisticStream* stream = create_stream(vhost, req);
|
||||
|
||||
stream->has_audio = true;
|
||||
stream->acodec = acodec;
|
||||
stream->asample_rate = asample_rate;
|
||||
stream->asound_type = asound_type;
|
||||
stream->aac_object = aac_object;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SrsStatistic::on_stream_close(SrsRequest* req)
|
||||
{
|
||||
SrsStatisticVhost* vhost = create_vhost(req);
|
||||
SrsStatisticStream* stream = create_stream(vhost, req);
|
||||
|
||||
stream->close();
|
||||
}
|
||||
|
||||
int SrsStatistic::on_client(int id, SrsRequest* req)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// create vhost if not exists.
|
||||
SrsStatisticVhost* vhost = NULL;
|
||||
if (vhosts.find(req->vhost) == vhosts.end()) {
|
||||
vhost = new SrsStatisticVhost();
|
||||
vhost->vhost = req->vhost;
|
||||
vhosts[req->vhost] = vhost;
|
||||
} else {
|
||||
vhost = vhosts[req->vhost];
|
||||
}
|
||||
|
||||
// the url to identify the stream.
|
||||
std::string url = req->get_stream_url();
|
||||
|
||||
// create stream if not exists.
|
||||
SrsStatisticStream* stream = NULL;
|
||||
if (streams.find(url) == streams.end()) {
|
||||
stream = new SrsStatisticStream();
|
||||
stream->vhost = vhost;
|
||||
stream->stream = req->stream;
|
||||
stream->url = url;
|
||||
streams[url] = stream;
|
||||
} else {
|
||||
stream = streams[url];
|
||||
}
|
||||
SrsStatisticVhost* vhost = create_vhost(req);
|
||||
SrsStatisticStream* stream = create_stream(vhost, req);
|
||||
|
||||
// create client if not exists
|
||||
SrsStatisticClient* client = NULL;
|
||||
|
@ -135,7 +187,7 @@ int SrsStatistic::on_client(int id, SrsRequest* req)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void SrsStatistic::on_close(int id)
|
||||
void SrsStatistic::on_disconnect(int id)
|
||||
{
|
||||
std::map<int, SrsStatisticClient*>::iterator it;
|
||||
it = clients.find(id);
|
||||
|
@ -146,6 +198,49 @@ void SrsStatistic::on_close(int id)
|
|||
}
|
||||
}
|
||||
|
||||
void SrsStatistic::kbps_add_delta(SrsConnection* conn)
|
||||
{
|
||||
int id = conn->srs_id();
|
||||
if (clients.find(id) == clients.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SrsStatisticClient* client = clients[id];
|
||||
|
||||
// resample the kbps to collect the delta.
|
||||
conn->resample();
|
||||
|
||||
// add delta of connection to kbps.
|
||||
// for next sample() of server kbps can get the stat.
|
||||
kbps->add_delta(conn);
|
||||
client->stream->kbps->add_delta(conn);
|
||||
client->stream->vhost->kbps->add_delta(conn);
|
||||
|
||||
// cleanup the delta.
|
||||
conn->cleanup();
|
||||
}
|
||||
|
||||
SrsKbps* SrsStatistic::kbps_sample()
|
||||
{
|
||||
kbps->sample();
|
||||
if (true) {
|
||||
std::map<std::string, SrsStatisticVhost*>::iterator it;
|
||||
for (it = vhosts.begin(); it != vhosts.end(); it++) {
|
||||
SrsStatisticVhost* vhost = it->second;
|
||||
vhost->kbps->sample();
|
||||
}
|
||||
}
|
||||
if (true) {
|
||||
std::map<std::string, SrsStatisticStream*>::iterator it;
|
||||
for (it = streams.begin(); it != streams.end(); it++) {
|
||||
SrsStatisticStream* stream = it->second;
|
||||
stream->kbps->sample();
|
||||
}
|
||||
}
|
||||
|
||||
return kbps;
|
||||
}
|
||||
|
||||
int64_t SrsStatistic::server_id()
|
||||
{
|
||||
return _server_id;
|
||||
|
@ -165,7 +260,9 @@ int SrsStatistic::dumps_vhosts(stringstream& ss)
|
|||
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_ORG("id", vhost->id) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("name", vhost->vhost)
|
||||
<< __SRS_JFIELD_STR("name", vhost->vhost) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("send_bytes", vhost->kbps->get_send_bytes()) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("recv_bytes", vhost->kbps->get_recv_bytes())
|
||||
<< __SRS_JOBJECT_END;
|
||||
}
|
||||
ss << __SRS_JARRAY_END;
|
||||
|
@ -198,10 +295,76 @@ int SrsStatistic::dumps_streams(stringstream& ss)
|
|||
<< __SRS_JFIELD_ORG("id", stream->id) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("name", stream->stream) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("vhost", stream->vhost->id) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("clients", client_num)
|
||||
<< __SRS_JOBJECT_END;
|
||||
<< __SRS_JFIELD_ORG("clients", client_num) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("send_bytes", stream->kbps->get_send_bytes()) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("recv_bytes", stream->kbps->get_recv_bytes()) << __SRS_JFIELD_CONT;
|
||||
|
||||
if (!stream->has_video) {
|
||||
ss << __SRS_JFIELD_NULL("video") << __SRS_JFIELD_CONT;
|
||||
} else {
|
||||
ss << __SRS_JFIELD_NAME("video")
|
||||
<< __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_STR("codec", srs_codec_video2str(stream->vcodec)) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("profile", srs_codec_avc_profile2str(stream->avc_profile)) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("level", srs_codec_avc_level2str(stream->avc_level))
|
||||
<< __SRS_JOBJECT_END
|
||||
<< __SRS_JFIELD_CONT;
|
||||
}
|
||||
|
||||
if (!stream->has_audio) {
|
||||
ss << __SRS_JFIELD_NULL("audio");
|
||||
} else {
|
||||
ss << __SRS_JFIELD_NAME("audio")
|
||||
<< __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_STR("codec", srs_codec_audio2str(stream->acodec)) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("sample_rate", (int)flv_sample_rates[stream->asample_rate]) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("channel", (int)stream->asound_type + 1) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("profile", srs_codec_aac_object2str(stream->aac_object))
|
||||
<< __SRS_JOBJECT_END;
|
||||
}
|
||||
|
||||
ss << __SRS_JOBJECT_END;
|
||||
}
|
||||
ss << __SRS_JARRAY_END;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsStatisticVhost* SrsStatistic::create_vhost(SrsRequest* req)
|
||||
{
|
||||
SrsStatisticVhost* vhost = NULL;
|
||||
|
||||
// create vhost if not exists.
|
||||
if (vhosts.find(req->vhost) == vhosts.end()) {
|
||||
vhost = new SrsStatisticVhost();
|
||||
vhost->vhost = req->vhost;
|
||||
vhosts[req->vhost] = vhost;
|
||||
return vhost;
|
||||
}
|
||||
|
||||
vhost = vhosts[req->vhost];
|
||||
|
||||
return vhost;
|
||||
}
|
||||
|
||||
SrsStatisticStream* SrsStatistic::create_stream(SrsStatisticVhost* vhost, SrsRequest* req)
|
||||
{
|
||||
std::string url = req->get_stream_url();
|
||||
|
||||
SrsStatisticStream* stream = NULL;
|
||||
|
||||
// create stream if not exists.
|
||||
if (streams.find(url) == streams.end()) {
|
||||
stream = new SrsStatisticStream();
|
||||
stream->vhost = vhost;
|
||||
stream->stream = req->stream;
|
||||
stream->url = url;
|
||||
streams[url] = stream;
|
||||
return stream;
|
||||
}
|
||||
|
||||
stream = streams[url];
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,13 +33,22 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <srs_kernel_codec.hpp>
|
||||
|
||||
class SrsKbps;
|
||||
class SrsRequest;
|
||||
class SrsConnection;
|
||||
|
||||
struct SrsStatisticVhost
|
||||
{
|
||||
public:
|
||||
int64_t id;
|
||||
std::string vhost;
|
||||
public:
|
||||
/**
|
||||
* vhost total kbps.
|
||||
*/
|
||||
SrsKbps* kbps;
|
||||
public:
|
||||
SrsStatisticVhost();
|
||||
virtual ~SrsStatisticVhost();
|
||||
|
@ -53,9 +62,38 @@ public:
|
|||
std::string app;
|
||||
std::string stream;
|
||||
std::string url;
|
||||
public:
|
||||
/**
|
||||
* stream total kbps.
|
||||
*/
|
||||
SrsKbps* kbps;
|
||||
public:
|
||||
bool has_video;
|
||||
SrsCodecVideo vcodec;
|
||||
// profile_idc, H.264-AVC-ISO_IEC_14496-10.pdf, page 45.
|
||||
SrsAvcProfile avc_profile;
|
||||
// level_idc, H.264-AVC-ISO_IEC_14496-10.pdf, page 45.
|
||||
SrsAvcLevel avc_level;
|
||||
public:
|
||||
bool has_audio;
|
||||
SrsCodecAudio acodec;
|
||||
SrsCodecAudioSampleRate asample_rate;
|
||||
SrsCodecAudioSoundType asound_type;
|
||||
/**
|
||||
* audio specified
|
||||
* audioObjectType, in 1.6.2.1 AudioSpecificConfig, page 33,
|
||||
* 1.5.1.1 Audio object type definition, page 23,
|
||||
* in aac-mp4a-format-ISO_IEC_14496-3+2001.pdf.
|
||||
*/
|
||||
SrsAacObjectType aac_object;
|
||||
public:
|
||||
SrsStatisticStream();
|
||||
virtual ~SrsStatisticStream();
|
||||
public:
|
||||
/**
|
||||
* close the stream.
|
||||
*/
|
||||
virtual void close();
|
||||
};
|
||||
|
||||
struct SrsStatisticClient
|
||||
|
@ -73,15 +111,35 @@ private:
|
|||
int64_t _server_id;
|
||||
// key: vhost name, value: vhost object.
|
||||
std::map<std::string, SrsStatisticVhost*> vhosts;
|
||||
// key: stream name, value: stream object.
|
||||
// key: stream url, value: stream object.
|
||||
std::map<std::string, SrsStatisticStream*> streams;
|
||||
// key: client id, value: stream object.
|
||||
std::map<int, SrsStatisticClient*> clients;
|
||||
// server total kbps.
|
||||
SrsKbps* kbps;
|
||||
private:
|
||||
SrsStatistic();
|
||||
virtual ~SrsStatistic();
|
||||
public:
|
||||
static SrsStatistic* instance();
|
||||
public:
|
||||
/**
|
||||
* when got video info for stream.
|
||||
*/
|
||||
virtual int on_video_info(SrsRequest* req,
|
||||
SrsCodecVideo vcodec, SrsAvcProfile avc_profile, SrsAvcLevel avc_level
|
||||
);
|
||||
/**
|
||||
* when got audio info for stream.
|
||||
*/
|
||||
virtual int on_audio_info(SrsRequest* req,
|
||||
SrsCodecAudio acodec, SrsCodecAudioSampleRate asample_rate, SrsCodecAudioSoundType asound_type,
|
||||
SrsAacObjectType aac_object
|
||||
);
|
||||
/**
|
||||
* when close stream.
|
||||
*/
|
||||
virtual void on_stream_close(SrsRequest* req);
|
||||
public:
|
||||
/**
|
||||
* when got a client to publish/play stream,
|
||||
|
@ -90,9 +148,19 @@ public:
|
|||
*/
|
||||
virtual int on_client(int id, SrsRequest* req);
|
||||
/**
|
||||
* client close
|
||||
* client disconnect
|
||||
*/
|
||||
virtual void on_close(int id);
|
||||
virtual void on_disconnect(int id);
|
||||
/**
|
||||
* sample the kbps, add delta bytes of conn.
|
||||
* use kbps_sample() to get all result of kbps stat.
|
||||
*/
|
||||
virtual void kbps_add_delta(SrsConnection* conn);
|
||||
/**
|
||||
* calc the result for all kbps.
|
||||
* @return the server kbps.
|
||||
*/
|
||||
virtual SrsKbps* kbps_sample();
|
||||
public:
|
||||
/**
|
||||
* get the server id, used to identify the server.
|
||||
|
@ -107,6 +175,9 @@ public:
|
|||
* dumps the streams to sstream in json.
|
||||
*/
|
||||
virtual int dumps_streams(std::stringstream& ss);
|
||||
private:
|
||||
virtual SrsStatisticVhost* create_vhost(SrsRequest* req);
|
||||
virtual SrsStatisticStream* create_stream(SrsStatisticVhost* vhost, SrsRequest* req);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1119,9 +1119,7 @@ void srs_api_dump_summaries(std::stringstream& ss)
|
|||
<< __SRS_JFIELD_ORG("net_send_bytes", ns_bytes) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("srs_sample_time", nrs->sample_time) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("srs_recv_bytes", nrs->rbytes) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("srs_recv_kbps", nrs->rkbps) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("srs_send_bytes", nrs->sbytes) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("srs_send_kbps", nrs->skbps) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("conn_sys", nrs->nb_conn_sys) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("conn_sys_et", nrs->nb_conn_sys_et) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("conn_sys_tw", nrs->nb_conn_sys_tw) << __SRS_JFIELD_CONT
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue