mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Copy 4.0release
This commit is contained in:
parent
00395588bc
commit
5e3e013c60
183 changed files with 27373 additions and 13949 deletions
|
@ -26,6 +26,7 @@
|
|||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
using namespace std;
|
||||
|
||||
#include <srs_kernel_log.hpp>
|
||||
|
@ -46,9 +47,6 @@ using namespace std;
|
|||
#include <srs_protocol_amf0.hpp>
|
||||
#include <srs_protocol_utility.hpp>
|
||||
#include <srs_app_coworkers.hpp>
|
||||
#ifdef SRS_AUTO_RTC
|
||||
#include <srs_app_rtc_conn.hpp>
|
||||
#endif
|
||||
|
||||
srs_error_t srs_api_response_jsonp(ISrsHttpResponseWriter* w, string callback, string data)
|
||||
{
|
||||
|
@ -196,13 +194,25 @@ srs_error_t SrsGoApiRoot::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage*
|
|||
SrsAutoFree(SrsJsonObject, obj);
|
||||
|
||||
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
obj->set("server", SrsJsonAny::integer(stat->server_id()));
|
||||
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
||||
|
||||
SrsJsonObject* urls = SrsJsonAny::object();
|
||||
obj->set("urls", urls);
|
||||
|
||||
urls->set("api", SrsJsonAny::str("the api root"));
|
||||
|
||||
|
||||
if (true) {
|
||||
SrsJsonObject* rtc = SrsJsonAny::object();
|
||||
urls->set("rtc", rtc);
|
||||
|
||||
SrsJsonObject* v1 = SrsJsonAny::object();
|
||||
rtc->set("v1", v1);
|
||||
|
||||
v1->set("play", SrsJsonAny::str("Play stream"));
|
||||
v1->set("publish", SrsJsonAny::str("Publish stream"));
|
||||
v1->set("nack", SrsJsonAny::str("Simulate the NACK"));
|
||||
}
|
||||
|
||||
return srs_api_response(w, r, obj->dumps());
|
||||
}
|
||||
|
||||
|
@ -222,7 +232,7 @@ srs_error_t SrsGoApiApi::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage*
|
|||
SrsAutoFree(SrsJsonObject, obj);
|
||||
|
||||
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
obj->set("server", SrsJsonAny::integer(stat->server_id()));
|
||||
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
||||
|
||||
SrsJsonObject* urls = SrsJsonAny::object();
|
||||
obj->set("urls", urls);
|
||||
|
@ -248,7 +258,7 @@ srs_error_t SrsGoApiV1::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r
|
|||
SrsAutoFree(SrsJsonObject, obj);
|
||||
|
||||
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
obj->set("server", SrsJsonAny::integer(stat->server_id()));
|
||||
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
||||
|
||||
SrsJsonObject* urls = SrsJsonAny::object();
|
||||
obj->set("urls", urls);
|
||||
|
@ -297,7 +307,7 @@ srs_error_t SrsGoApiVersion::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa
|
|||
SrsAutoFree(SrsJsonObject, obj);
|
||||
|
||||
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
obj->set("server", SrsJsonAny::integer(stat->server_id()));
|
||||
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
||||
|
||||
SrsJsonObject* data = SrsJsonAny::object();
|
||||
obj->set("data", data);
|
||||
|
@ -326,7 +336,7 @@ srs_error_t SrsGoApiSummaries::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMes
|
|||
SrsAutoFree(SrsJsonObject, obj);
|
||||
|
||||
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
obj->set("server", SrsJsonAny::integer(stat->server_id()));
|
||||
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
||||
|
||||
srs_api_dump_summaries(obj);
|
||||
|
||||
|
@ -349,7 +359,7 @@ srs_error_t SrsGoApiRusages::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa
|
|||
SrsAutoFree(SrsJsonObject, obj);
|
||||
|
||||
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
obj->set("server", SrsJsonAny::integer(stat->server_id()));
|
||||
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
||||
|
||||
SrsJsonObject* data = SrsJsonAny::object();
|
||||
obj->set("data", data);
|
||||
|
@ -394,7 +404,7 @@ srs_error_t SrsGoApiSelfProcStats::serve_http(ISrsHttpResponseWriter* w, ISrsHtt
|
|||
SrsAutoFree(SrsJsonObject, obj);
|
||||
|
||||
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
obj->set("server", SrsJsonAny::integer(stat->server_id()));
|
||||
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
||||
|
||||
SrsJsonObject* data = SrsJsonAny::object();
|
||||
obj->set("data", data);
|
||||
|
@ -471,7 +481,7 @@ srs_error_t SrsGoApiSystemProcStats::serve_http(ISrsHttpResponseWriter* w, ISrsH
|
|||
SrsAutoFree(SrsJsonObject, obj);
|
||||
|
||||
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
obj->set("server", SrsJsonAny::integer(stat->server_id()));
|
||||
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
||||
|
||||
SrsJsonObject* data = SrsJsonAny::object();
|
||||
obj->set("data", data);
|
||||
|
@ -510,7 +520,7 @@ srs_error_t SrsGoApiMemInfos::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
|
|||
SrsAutoFree(SrsJsonObject, obj);
|
||||
|
||||
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
obj->set("server", SrsJsonAny::integer(stat->server_id()));
|
||||
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
||||
|
||||
SrsJsonObject* data = SrsJsonAny::object();
|
||||
obj->set("data", data);
|
||||
|
@ -550,13 +560,13 @@ srs_error_t SrsGoApiAuthors::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa
|
|||
SrsAutoFree(SrsJsonObject, obj);
|
||||
|
||||
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
obj->set("server", SrsJsonAny::integer(stat->server_id()));
|
||||
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
||||
|
||||
SrsJsonObject* data = SrsJsonAny::object();
|
||||
obj->set("data", data);
|
||||
|
||||
data->set("license", SrsJsonAny::str(RTMP_SIG_SRS_LICENSE));
|
||||
data->set("contributors", SrsJsonAny::str(SRS_AUTO_CONSTRIBUTORS));
|
||||
data->set("contributors", SrsJsonAny::str(SRS_CONSTRIBUTORS));
|
||||
|
||||
return srs_api_response(w, r, obj->dumps());
|
||||
}
|
||||
|
@ -577,22 +587,22 @@ srs_error_t SrsGoApiFeatures::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
|
|||
SrsAutoFree(SrsJsonObject, obj);
|
||||
|
||||
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
obj->set("server", SrsJsonAny::integer(stat->server_id()));
|
||||
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
||||
|
||||
SrsJsonObject* data = SrsJsonAny::object();
|
||||
obj->set("data", data);
|
||||
|
||||
data->set("options", SrsJsonAny::str(SRS_AUTO_USER_CONFIGURE));
|
||||
data->set("options2", SrsJsonAny::str(SRS_AUTO_CONFIGURE));
|
||||
data->set("build", SrsJsonAny::str(SRS_AUTO_BUILD_DATE));
|
||||
data->set("build2", SrsJsonAny::str(SRS_AUTO_BUILD_TS));
|
||||
data->set("options", SrsJsonAny::str(SRS_USER_CONFIGURE));
|
||||
data->set("options2", SrsJsonAny::str(SRS_CONFIGURE));
|
||||
data->set("build", SrsJsonAny::str(SRS_BUILD_DATE));
|
||||
data->set("build2", SrsJsonAny::str(SRS_BUILD_TS));
|
||||
|
||||
SrsJsonObject* features = SrsJsonAny::object();
|
||||
data->set("features", features);
|
||||
|
||||
features->set("ssl", SrsJsonAny::boolean(true));
|
||||
features->set("hls", SrsJsonAny::boolean(true));
|
||||
#ifdef SRS_AUTO_HDS
|
||||
#ifdef SRS_HDS
|
||||
features->set("hds", SrsJsonAny::boolean(true));
|
||||
#else
|
||||
features->set("hds", SrsJsonAny::boolean(false));
|
||||
|
@ -645,7 +655,7 @@ srs_error_t SrsGoApiRequests::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
|
|||
SrsAutoFree(SrsJsonObject, obj);
|
||||
|
||||
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
obj->set("server", SrsJsonAny::integer(stat->server_id()));
|
||||
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
||||
|
||||
SrsJsonObject* data = SrsJsonAny::object();
|
||||
obj->set("data", data);
|
||||
|
@ -689,10 +699,10 @@ srs_error_t SrsGoApiVhosts::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessag
|
|||
|
||||
// path: {pattern}{vhost_id}
|
||||
// e.g. /api/v1/vhosts/100 pattern= /api/v1/vhosts/, vhost_id=100
|
||||
int vid = r->parse_rest_id(entry->pattern);
|
||||
string vid = r->parse_rest_id(entry->pattern);
|
||||
SrsStatisticVhost* vhost = NULL;
|
||||
|
||||
if (vid > 0 && (vhost = stat->find_vhost(vid)) == NULL) {
|
||||
if (!vid.empty() && (vhost = stat->find_vhost_by_id(vid)) == NULL) {
|
||||
return srs_api_response_code(w, r, ERROR_RTMP_VHOST_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
@ -700,7 +710,7 @@ srs_error_t SrsGoApiVhosts::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessag
|
|||
SrsAutoFree(SrsJsonObject, obj);
|
||||
|
||||
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
obj->set("server", SrsJsonAny::integer(stat->server_id()));
|
||||
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
||||
|
||||
if (r->is_http_get()) {
|
||||
if (!vhost) {
|
||||
|
@ -745,10 +755,10 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa
|
|||
|
||||
// path: {pattern}{stream_id}
|
||||
// e.g. /api/v1/streams/100 pattern= /api/v1/streams/, stream_id=100
|
||||
int sid = r->parse_rest_id(entry->pattern);
|
||||
string sid = r->parse_rest_id(entry->pattern);
|
||||
|
||||
SrsStatisticStream* stream = NULL;
|
||||
if (sid >= 0 && (stream = stat->find_stream(sid)) == NULL) {
|
||||
if (!sid.empty() && (stream = stat->find_stream(sid)) == NULL) {
|
||||
return srs_api_response_code(w, r, ERROR_RTMP_STREAM_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
@ -756,7 +766,7 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa
|
|||
SrsAutoFree(SrsJsonObject, obj);
|
||||
|
||||
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
obj->set("server", SrsJsonAny::integer(stat->server_id()));
|
||||
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
||||
|
||||
if (r->is_http_get()) {
|
||||
if (!stream) {
|
||||
|
@ -785,314 +795,6 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa
|
|||
return srs_api_response(w, r, obj->dumps());
|
||||
}
|
||||
|
||||
#ifdef SRS_AUTO_RTC
|
||||
uint32_t SrsGoApiRtcPlay::ssrc_num = 0;
|
||||
|
||||
SrsGoApiRtcPlay::SrsGoApiRtcPlay(SrsRtcServer* rtc_svr)
|
||||
{
|
||||
rtc_server = rtc_svr;
|
||||
}
|
||||
|
||||
SrsGoApiRtcPlay::~SrsGoApiRtcPlay()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// Request:
|
||||
// POST /rtc/v1/play/
|
||||
// {
|
||||
// "sdp":"offer...", "streamurl":"webrtc://r.ossrs.net/live/livestream",
|
||||
// "api":'http...", "clientip":"..."
|
||||
// }
|
||||
// Response:
|
||||
// {"sdp":"answer...", "sid":"..."}
|
||||
// @see https://github.com/rtcdn/rtcdn-draft
|
||||
srs_error_t SrsGoApiRtcPlay::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
SrsJsonObject* res = SrsJsonAny::object();
|
||||
SrsAutoFree(SrsJsonObject, res);
|
||||
|
||||
if ((err = do_serve_http(w, r, res)) != srs_success) {
|
||||
srs_warn("RTC error %s", srs_error_desc(err).c_str()); srs_freep(err);
|
||||
return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest);
|
||||
}
|
||||
|
||||
return srs_api_response(w, r, res->dumps());
|
||||
}
|
||||
|
||||
srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, SrsJsonObject* res)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// For each RTC session, we use short-term HTTP connection.
|
||||
SrsHttpHeader* hdr = w->header();
|
||||
hdr->set("Connection", "Close");
|
||||
|
||||
// Parse req, the request json object, from body.
|
||||
SrsJsonObject* req = NULL;
|
||||
SrsAutoFree(SrsJsonObject, req);
|
||||
if (true) {
|
||||
string req_json;
|
||||
if ((err = r->body_read_all(req_json)) != srs_success) {
|
||||
return srs_error_wrap(err, "read body");
|
||||
}
|
||||
|
||||
SrsJsonAny* json = SrsJsonAny::loads(req_json);
|
||||
if (!json || !json->is_object()) {
|
||||
return srs_error_wrap(err, "not json");
|
||||
}
|
||||
|
||||
req = json->to_object();
|
||||
}
|
||||
|
||||
// Fetch params from req object.
|
||||
SrsJsonAny* prop = NULL;
|
||||
if ((prop = req->ensure_property_string("sdp")) == NULL) {
|
||||
return srs_error_wrap(err, "not sdp");
|
||||
}
|
||||
string remote_sdp_str = prop->to_str();
|
||||
|
||||
if ((prop = req->ensure_property_string("streamurl")) == NULL) {
|
||||
return srs_error_wrap(err, "not streamurl");
|
||||
}
|
||||
string streamurl = prop->to_str();
|
||||
|
||||
string clientip;
|
||||
if ((prop = req->ensure_property_string("clientip")) != NULL) {
|
||||
clientip = prop->to_str();
|
||||
}
|
||||
|
||||
string api;
|
||||
if ((prop = req->ensure_property_string("api")) != NULL) {
|
||||
api = prop->to_str();
|
||||
}
|
||||
|
||||
// TODO: FIXME: Parse vhost.
|
||||
// Parse app and stream from streamurl.
|
||||
string app;
|
||||
string stream_name;
|
||||
if (true) {
|
||||
string tcUrl;
|
||||
srs_parse_rtmp_url(streamurl, tcUrl, stream_name);
|
||||
|
||||
int port;
|
||||
string schema, host, vhost, param;
|
||||
srs_discovery_tc_url(tcUrl, schema, host, vhost, app, stream_name, port, param);
|
||||
}
|
||||
|
||||
// For client to specifies the EIP of server.
|
||||
string eip = r->query_get("eip");
|
||||
// For client to specifies whether encrypt by SRTP.
|
||||
string encrypt = r->query_get("encrypt");
|
||||
|
||||
srs_trace("RTC play %s, api=%s, clientip=%s, app=%s, stream=%s, offer=%dB, eip=%s, encrypt=%s",
|
||||
streamurl.c_str(), api.c_str(), clientip.c_str(), app.c_str(), stream_name.c_str(), remote_sdp_str.length(),
|
||||
eip.c_str(), encrypt.c_str());
|
||||
|
||||
// TODO: FIXME: It seems remote_sdp doesn't represents the full SDP information.
|
||||
SrsSdp remote_sdp;
|
||||
if ((err = remote_sdp.parse(remote_sdp_str)) != srs_success) {
|
||||
return srs_error_wrap(err, "parse sdp failed: %s", remote_sdp_str.c_str());
|
||||
}
|
||||
|
||||
if ((err = check_remote_sdp(remote_sdp)) != srs_success) {
|
||||
return srs_error_wrap(err, "remote sdp check failed");
|
||||
}
|
||||
|
||||
SrsSdp local_sdp;
|
||||
if ((err = exchange_sdp(app, stream_name, remote_sdp, local_sdp)) != srs_success) {
|
||||
return srs_error_wrap(err, "remote sdp have error or unsupport attributes");
|
||||
}
|
||||
|
||||
SrsRequest request;
|
||||
request.app = app;
|
||||
request.stream = stream_name;
|
||||
|
||||
// TODO: FIXME: Parse vhost.
|
||||
// discovery vhost, resolve the vhost from config
|
||||
SrsConfDirective* parsed_vhost = _srs_config->get_vhost("");
|
||||
if (parsed_vhost) {
|
||||
request.vhost = parsed_vhost->arg0();
|
||||
}
|
||||
|
||||
// TODO: FIXME: Maybe need a better name?
|
||||
// TODO: FIXME: When server enabled, but vhost disabled, should report error.
|
||||
SrsRtcSession* rtc_session = rtc_server->create_rtc_session(request, remote_sdp, local_sdp, eip);
|
||||
if (encrypt.empty()) {
|
||||
rtc_session->set_encrypt(_srs_config->get_rtc_server_encrypt());
|
||||
} else {
|
||||
rtc_session->set_encrypt(encrypt != "false");
|
||||
}
|
||||
|
||||
ostringstream os;
|
||||
if ((err = local_sdp.encode(os)) != srs_success) {
|
||||
return srs_error_wrap(err, "encode sdp");
|
||||
}
|
||||
|
||||
string local_sdp_str = os.str();
|
||||
|
||||
srs_verbose("local_sdp=%s", local_sdp_str.c_str());
|
||||
|
||||
res->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
res->set("server", SrsJsonAny::integer(SrsStatistic::instance()->server_id()));
|
||||
|
||||
// TODO: add candidates in response json?
|
||||
|
||||
res->set("sdp", SrsJsonAny::str(local_sdp_str.c_str()));
|
||||
res->set("sessionid", SrsJsonAny::str(rtc_session->id().c_str()));
|
||||
|
||||
srs_trace("RTC sid=%s, offer=%dB, answer=%dB", rtc_session->id().c_str(), remote_sdp_str.length(), local_sdp_str.length());
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsGoApiRtcPlay::check_remote_sdp(const SrsSdp& remote_sdp)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (remote_sdp.group_policy_ != "BUNDLE") {
|
||||
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "now only support BUNDLE, group policy=%s", remote_sdp.group_policy_.c_str());
|
||||
}
|
||||
|
||||
if (remote_sdp.media_descs_.empty()) {
|
||||
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "no media descriptions");
|
||||
}
|
||||
|
||||
for (std::vector<SrsMediaDesc>::const_iterator iter = remote_sdp.media_descs_.begin(); iter != remote_sdp.media_descs_.end(); ++iter) {
|
||||
if (iter->type_ != "audio" && iter->type_ != "video") {
|
||||
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "unsupport media type=%s", iter->type_.c_str());
|
||||
}
|
||||
|
||||
if (! iter->rtcp_mux_) {
|
||||
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "now only suppor rtcp-mux");
|
||||
}
|
||||
|
||||
for (std::vector<SrsMediaPayloadType>::const_iterator iter_media = iter->payload_types_.begin(); iter_media != iter->payload_types_.end(); ++iter_media) {
|
||||
if (iter->sendonly_) {
|
||||
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "play API only support sendrecv/recvonly");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsGoApiRtcPlay::exchange_sdp(const std::string& app, const std::string& stream, const SrsSdp& remote_sdp, SrsSdp& local_sdp)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
local_sdp.version_ = "0";
|
||||
|
||||
local_sdp.username_ = RTMP_SIG_SRS_SERVER;
|
||||
local_sdp.session_id_ = srs_int2str((int64_t)this);
|
||||
local_sdp.session_version_ = "2";
|
||||
local_sdp.nettype_ = "IN";
|
||||
local_sdp.addrtype_ = "IP4";
|
||||
local_sdp.unicast_address_ = "0.0.0.0";
|
||||
|
||||
local_sdp.session_name_ = "live_play_session";
|
||||
|
||||
local_sdp.msid_semantic_ = "WMS";
|
||||
local_sdp.msids_.push_back(app + "/" + stream);
|
||||
|
||||
local_sdp.group_policy_ = "BUNDLE";
|
||||
|
||||
for (size_t i = 0; i < remote_sdp.media_descs_.size(); ++i) {
|
||||
const SrsMediaDesc& remote_media_desc = remote_sdp.media_descs_[i];
|
||||
|
||||
if (remote_media_desc.is_audio()) {
|
||||
local_sdp.media_descs_.push_back(SrsMediaDesc("audio"));
|
||||
} else if (remote_media_desc.is_video()) {
|
||||
local_sdp.media_descs_.push_back(SrsMediaDesc("video"));
|
||||
}
|
||||
|
||||
SrsMediaDesc& local_media_desc = local_sdp.media_descs_.back();
|
||||
|
||||
if (remote_media_desc.is_audio()) {
|
||||
// TODO: check opus format specific param
|
||||
std::vector<SrsMediaPayloadType> payloads = remote_media_desc.find_media_with_encoding_name("opus");
|
||||
for (std::vector<SrsMediaPayloadType>::iterator iter = payloads.begin(); iter != payloads.end(); ++iter) {
|
||||
// Only choose one match opus codec.
|
||||
local_media_desc.payload_types_.push_back(*iter);
|
||||
break;
|
||||
}
|
||||
|
||||
if (local_media_desc.payload_types_.empty()) {
|
||||
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "no found valid opus payload type");
|
||||
}
|
||||
|
||||
} else if (remote_media_desc.is_video()) {
|
||||
std::deque<SrsMediaPayloadType> backup_payloads;
|
||||
std::vector<SrsMediaPayloadType> payloads = remote_media_desc.find_media_with_encoding_name("H264");
|
||||
for (std::vector<SrsMediaPayloadType>::iterator iter = payloads.begin(); iter != payloads.end(); ++iter) {
|
||||
if (iter->format_specific_param_.empty()) {
|
||||
backup_payloads.push_front(*iter);
|
||||
continue;
|
||||
}
|
||||
H264SpecificParam h264_param;
|
||||
if ((err = parse_h264_fmtp(iter->format_specific_param_, h264_param)) != srs_success) {
|
||||
srs_error_reset(err); continue;
|
||||
}
|
||||
|
||||
// Try to pick the "best match" H.264 payload type.
|
||||
if (h264_param.packetization_mode == "1" && h264_param.level_asymmerty_allow == "1") {
|
||||
// Only choose first match H.264 payload type.
|
||||
local_media_desc.payload_types_.push_back(*iter);
|
||||
break;
|
||||
}
|
||||
|
||||
backup_payloads.push_back(*iter);
|
||||
}
|
||||
|
||||
// Try my best to pick at least one media payload type.
|
||||
if (local_media_desc.payload_types_.empty() && ! backup_payloads.empty()) {
|
||||
srs_warn("choose backup H.264 payload type=%d", backup_payloads.front().payload_type_);
|
||||
local_media_desc.payload_types_.push_back(backup_payloads.front());
|
||||
}
|
||||
|
||||
if (local_media_desc.payload_types_.empty()) {
|
||||
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "no found valid H.264 payload type");
|
||||
}
|
||||
}
|
||||
|
||||
local_media_desc.mid_ = remote_media_desc.mid_;
|
||||
local_sdp.groups_.push_back(local_media_desc.mid_);
|
||||
|
||||
local_media_desc.port_ = 9;
|
||||
local_media_desc.protos_ = "UDP/TLS/RTP/SAVPF";
|
||||
|
||||
if (remote_media_desc.session_info_.setup_ == "active") {
|
||||
local_media_desc.session_info_.setup_ = "passive";
|
||||
} else if (remote_media_desc.session_info_.setup_ == "passive") {
|
||||
local_media_desc.session_info_.setup_ = "active";
|
||||
} else if (remote_media_desc.session_info_.setup_ == "actpass") {
|
||||
local_media_desc.session_info_.setup_ = "passive";
|
||||
}
|
||||
|
||||
if (remote_media_desc.sendonly_) {
|
||||
local_media_desc.recvonly_ = true;
|
||||
} else if (remote_media_desc.recvonly_) {
|
||||
local_media_desc.sendonly_ = true;
|
||||
} else if (remote_media_desc.sendrecv_) {
|
||||
local_media_desc.sendrecv_ = true;
|
||||
}
|
||||
|
||||
local_media_desc.rtcp_mux_ = true;
|
||||
local_media_desc.rtcp_rsize_ = true;
|
||||
|
||||
SrsSSRCInfo ssrc_info;
|
||||
ssrc_info.ssrc_ = ++ssrc_num;
|
||||
// TODO:use formated cname
|
||||
ssrc_info.cname_ = "test_sdp_cname";
|
||||
local_media_desc.ssrc_infos_.push_back(ssrc_info);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
SrsGoApiClients::SrsGoApiClients()
|
||||
{
|
||||
}
|
||||
|
@ -1109,10 +811,10 @@ srs_error_t SrsGoApiClients::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa
|
|||
|
||||
// path: {pattern}{client_id}
|
||||
// e.g. /api/v1/clients/100 pattern= /api/v1/clients/, client_id=100
|
||||
int cid = r->parse_rest_id(entry->pattern);
|
||||
string client_id = r->parse_rest_id(entry->pattern);
|
||||
|
||||
SrsStatisticClient* client = NULL;
|
||||
if (cid >= 0 && (client = stat->find_client(cid)) == NULL) {
|
||||
if (!client_id.empty() && (client = stat->find_client(client_id)) == NULL) {
|
||||
return srs_api_response_code(w, r, ERROR_RTMP_CLIENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
@ -1120,7 +822,7 @@ srs_error_t SrsGoApiClients::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa
|
|||
SrsAutoFree(SrsJsonObject, obj);
|
||||
|
||||
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
obj->set("server", SrsJsonAny::integer(stat->server_id()));
|
||||
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
||||
|
||||
if (r->is_http_get()) {
|
||||
if (!client) {
|
||||
|
@ -1150,9 +852,9 @@ srs_error_t SrsGoApiClients::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa
|
|||
if (!client) {
|
||||
return srs_api_response_code(w, r, ERROR_RTMP_CLIENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
||||
client->conn->expire();
|
||||
srs_warn("kickoff client id=%d ok", cid);
|
||||
srs_warn("kickoff client id=%s ok", client_id.c_str());
|
||||
} else {
|
||||
return srs_go_http_error(w, SRS_CONSTS_HTTP_MethodNotAllowed);
|
||||
}
|
||||
|
@ -1633,7 +1335,7 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage*
|
|||
|
||||
p->set("target", SrsJsonAny::str(target.c_str()));
|
||||
p->set("reset", SrsJsonAny::str(reset.c_str()));
|
||||
p->set("help", SrsJsonAny::str("?target=avframes|rtc|rtp|gso|writev_iovs|sendmmsg|bytes|dropped"));
|
||||
p->set("help", SrsJsonAny::str("?target=avframes|rtc|rtp|writev_iovs|bytes"));
|
||||
p->set("help2", SrsJsonAny::str("?reset=all"));
|
||||
}
|
||||
|
||||
|
@ -1669,24 +1371,6 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage*
|
|||
}
|
||||
}
|
||||
|
||||
if (target.empty() || target == "gso") {
|
||||
SrsJsonObject* p = SrsJsonAny::object();
|
||||
data->set("gso", p);
|
||||
if ((err = stat->dumps_perf_gso(p)) != srs_success) {
|
||||
int code = srs_error_code(err); srs_error_reset(err);
|
||||
return srs_api_response_code(w, r, code);
|
||||
}
|
||||
}
|
||||
|
||||
if (target.empty() || target == "sendmmsg") {
|
||||
SrsJsonObject* p = SrsJsonAny::object();
|
||||
data->set("sendmmsg", p);
|
||||
if ((err = stat->dumps_perf_sendmmsg(p)) != srs_success) {
|
||||
int code = srs_error_code(err); srs_error_reset(err);
|
||||
return srs_api_response_code(w, r, code);
|
||||
}
|
||||
}
|
||||
|
||||
if (target.empty() || target == "writev_iovs") {
|
||||
SrsJsonObject* p = SrsJsonAny::object();
|
||||
data->set("writev_iovs", p);
|
||||
|
@ -1705,15 +1389,6 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage*
|
|||
}
|
||||
}
|
||||
|
||||
if (target.empty() || target == "dropped") {
|
||||
SrsJsonObject* p = SrsJsonAny::object();
|
||||
data->set("dropped", p);
|
||||
if ((err = stat->dumps_perf_dropped(p)) != srs_success) {
|
||||
int code = srs_error_code(err); srs_error_reset(err);
|
||||
return srs_api_response_code(w, r, code);
|
||||
}
|
||||
}
|
||||
|
||||
return srs_api_response(w, r, obj->dumps());
|
||||
}
|
||||
|
||||
|
@ -1730,7 +1405,7 @@ srs_error_t SrsGoApiError::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage
|
|||
return srs_api_response_code(w, r, 100);
|
||||
}
|
||||
|
||||
#ifdef SRS_AUTO_GB28181
|
||||
#ifdef SRS_GB28181
|
||||
SrsGoApiGb28181::SrsGoApiGb28181()
|
||||
{
|
||||
}
|
||||
|
@ -1801,11 +1476,12 @@ srs_error_t SrsGoApiGb28181::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
|
|||
return srs_api_response(w, r, obj->dumps());
|
||||
|
||||
} else if(action == "delete_channel"){
|
||||
if (id.empty()){
|
||||
return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id");
|
||||
string chid = r->query_get("chid");
|
||||
if (id.empty() || chid.empty()){
|
||||
return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id or chid");
|
||||
}
|
||||
|
||||
if ((err = _srs_gb28181->delete_stream_channel(id)) != srs_success) {
|
||||
if ((err = _srs_gb28181->delete_stream_channel(id, chid)) != srs_success) {
|
||||
return srs_error_wrap(err, "delete stream channel");
|
||||
}
|
||||
|
||||
|
@ -1898,6 +1574,16 @@ srs_error_t SrsGoApiGb28181::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
|
|||
}
|
||||
|
||||
return srs_api_response_code(w, r, 0);
|
||||
} else if(action == "sip_query_devicelist"){
|
||||
SrsJsonArray* arr = SrsJsonAny::array();
|
||||
data->set("PlatformID", SrsJsonAny::str(_srs_gb28181->get_gb28181_config_ptr()->sip_serial.c_str()));
|
||||
data->set("DeviceList", arr);
|
||||
|
||||
if ((err = _srs_gb28181->query_device_list("", arr)) != srs_success) {
|
||||
return srs_error_wrap(err, "query device list");
|
||||
}
|
||||
|
||||
return srs_api_response(w, r, obj->dumps());
|
||||
} else if(action == "sip_query_session"){
|
||||
SrsJsonArray* arr = SrsJsonAny::array();
|
||||
data->set("sessions", arr);
|
||||
|
@ -1913,7 +1599,7 @@ srs_error_t SrsGoApiGb28181::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef SRS_AUTO_GPERF
|
||||
#ifdef SRS_GPERF
|
||||
#include <gperftools/malloc_extension.h>
|
||||
|
||||
SrsGoApiTcmalloc::SrsGoApiTcmalloc()
|
||||
|
@ -1999,126 +1685,149 @@ srs_error_t SrsGoApiTcmalloc::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
|
|||
}
|
||||
#endif
|
||||
|
||||
SrsHttpApi::SrsHttpApi(IConnectionManager* cm, srs_netfd_t fd, SrsHttpServeMux* m, string cip)
|
||||
: SrsConnection(cm, fd, cip)
|
||||
SrsHttpApi::SrsHttpApi(bool https, ISrsResourceManager* cm, srs_netfd_t fd, SrsHttpServeMux* m, string cip, int port)
|
||||
{
|
||||
mux = m;
|
||||
cors = new SrsHttpCorsMux();
|
||||
parser = new SrsHttpParser();
|
||||
|
||||
// Create a identify for this client.
|
||||
_srs_context->set_id(_srs_context->generate_id());
|
||||
|
||||
manager = cm;
|
||||
skt = new SrsTcpConnection(fd);
|
||||
|
||||
if (https) {
|
||||
ssl = new SrsSslConnection(skt);
|
||||
conn = new SrsHttpConn(this, ssl, m, cip, port);
|
||||
} else {
|
||||
ssl = NULL;
|
||||
conn = new SrsHttpConn(this, skt, m, cip, port);
|
||||
}
|
||||
|
||||
_srs_config->subscribe(this);
|
||||
}
|
||||
|
||||
SrsHttpApi::~SrsHttpApi()
|
||||
{
|
||||
srs_freep(parser);
|
||||
srs_freep(cors);
|
||||
|
||||
_srs_config->unsubscribe(this);
|
||||
|
||||
srs_freep(conn);
|
||||
srs_freep(ssl);
|
||||
srs_freep(skt);
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpApi::on_start()
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = conn->set_jsonp(true)) != srs_success) {
|
||||
return srs_error_wrap(err, "set jsonp");
|
||||
}
|
||||
|
||||
if (ssl) {
|
||||
srs_utime_t starttime = srs_update_system_time();
|
||||
string crt_file = _srs_config->get_https_api_ssl_cert();
|
||||
string key_file = _srs_config->get_https_api_ssl_key();
|
||||
if ((err = ssl->handshake(key_file, crt_file)) != srs_success) {
|
||||
return srs_error_wrap(err, "handshake");
|
||||
}
|
||||
|
||||
int cost = srsu2msi(srs_update_system_time() - starttime);
|
||||
srs_trace("https: api server done, use key %s and cert %s, cost=%dms",
|
||||
key_file.c_str(), crt_file.c_str(), cost);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpApi::on_http_message(ISrsHttpMessage* r, SrsHttpResponseWriter* w)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// After parsed the message, set the schema to https.
|
||||
if (ssl) {
|
||||
SrsHttpMessage* hm = dynamic_cast<SrsHttpMessage*>(r);
|
||||
hm->set_https(true);
|
||||
}
|
||||
|
||||
// TODO: For each API session, we use short-term HTTP connection.
|
||||
//SrsHttpHeader* hdr = w->header();
|
||||
//hdr->set("Connection", "Close");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpApi::on_message_done(ISrsHttpMessage* r, SrsHttpResponseWriter* w)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// read all rest bytes in request body.
|
||||
char buf[SRS_HTTP_READ_CACHE_BYTES];
|
||||
ISrsHttpResponseReader* br = r->body_reader();
|
||||
while (!br->eof()) {
|
||||
if ((err = br->read(buf, SRS_HTTP_READ_CACHE_BYTES, NULL)) != srs_success) {
|
||||
return srs_error_wrap(err, "read response");
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpApi::on_conn_done(srs_error_t r0)
|
||||
{
|
||||
// Because we use manager to manage this object,
|
||||
// not the http connection object, so we must remove it here.
|
||||
manager->remove(this);
|
||||
|
||||
// For HTTP-API timeout, we think it's done successfully,
|
||||
// because there may be no request or response for HTTP-API.
|
||||
if (srs_error_code(r0) == ERROR_SOCKET_TIMEOUT) {
|
||||
srs_freep(r0);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
return r0;
|
||||
}
|
||||
|
||||
std::string SrsHttpApi::desc()
|
||||
{
|
||||
if (ssl) {
|
||||
return "HttpsConn";
|
||||
}
|
||||
return "HttpConn";
|
||||
}
|
||||
|
||||
void SrsHttpApi::remark(int64_t* in, int64_t* out)
|
||||
{
|
||||
// TODO: FIXME: implements it
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpApi::do_cycle()
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
srs_trace("API server client, ip=%s", ip.c_str());
|
||||
|
||||
// initialize parser
|
||||
if ((err = parser->initialize(HTTP_REQUEST, true)) != srs_success) {
|
||||
return srs_error_wrap(err, "init parser");
|
||||
}
|
||||
|
||||
// set the recv timeout, for some clients never disconnect the connection.
|
||||
// @see https://github.com/ossrs/srs/issues/398
|
||||
skt->set_recv_timeout(SRS_HTTP_RECV_TIMEOUT);
|
||||
|
||||
// initialize the cors, which will proxy to mux.
|
||||
bool crossdomain_enabled = _srs_config->get_http_api_crossdomain();
|
||||
if ((err = cors->initialize(mux, crossdomain_enabled)) != srs_success) {
|
||||
return srs_error_wrap(err, "init cors");
|
||||
}
|
||||
|
||||
// process http messages.
|
||||
while ((err = trd->pull()) == srs_success) {
|
||||
ISrsHttpMessage* req = NULL;
|
||||
|
||||
// get a http message
|
||||
if ((err = parser->parse_message(skt, &req)) != srs_success) {
|
||||
// For HTTP timeout, we think it's ok.
|
||||
if (srs_error_code(err) == ERROR_SOCKET_TIMEOUT) {
|
||||
srs_freep(err);
|
||||
return srs_error_wrap(srs_success, "http api timeout");
|
||||
}
|
||||
return srs_error_wrap(err, "parse message");
|
||||
}
|
||||
|
||||
// if SUCCESS, always NOT-NULL.
|
||||
// always free it in this scope.
|
||||
srs_assert(req);
|
||||
SrsAutoFree(ISrsHttpMessage, req);
|
||||
|
||||
// Attach owner connection to message.
|
||||
SrsHttpMessage* hreq = (SrsHttpMessage*)req;
|
||||
hreq->set_connection(this);
|
||||
|
||||
// ok, handle http request.
|
||||
SrsHttpResponseWriter writer(skt);
|
||||
if ((err = process_request(&writer, req)) != srs_success) {
|
||||
return srs_error_wrap(err, "process request");
|
||||
}
|
||||
|
||||
// read all rest bytes in request body.
|
||||
char buf[SRS_HTTP_READ_CACHE_BYTES];
|
||||
ISrsHttpResponseReader* br = req->body_reader();
|
||||
while (!br->eof()) {
|
||||
if ((err = br->read(buf, SRS_HTTP_READ_CACHE_BYTES, NULL)) != srs_success) {
|
||||
return srs_error_wrap(err, "read response");
|
||||
}
|
||||
}
|
||||
|
||||
// donot keep alive, disconnect it.
|
||||
// @see https://github.com/ossrs/srs/issues/399
|
||||
if (!req->is_keep_alive()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpApi::process_request(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
SrsHttpMessage* hm = dynamic_cast<SrsHttpMessage*>(r);
|
||||
srs_assert(hm);
|
||||
|
||||
srs_trace("HTTP API %s %s, content-length=%" PRId64 ", chunked=%d/%d",
|
||||
r->method_str().c_str(), r->url().c_str(), r->content_length(),
|
||||
hm->is_chunked(), hm->is_infinite_chunked());
|
||||
|
||||
// use cors server mux to serve http request, which will proxy to mux.
|
||||
if ((err = cors->serve_http(w, r)) != srs_success) {
|
||||
return srs_error_wrap(err, "mux serve");
|
||||
}
|
||||
|
||||
return err;
|
||||
conn->remark(in, out);
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpApi::on_reload_http_api_crossdomain()
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
bool crossdomain_enabled = _srs_config->get_http_api_crossdomain();
|
||||
if ((err = cors->initialize(mux, crossdomain_enabled)) != srs_success) {
|
||||
return srs_error_wrap(err, "reload");
|
||||
}
|
||||
|
||||
return err;
|
||||
bool v = _srs_config->get_http_api_crossdomain();
|
||||
return conn->set_crossdomain_enabled(v);
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpApi::start()
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
bool v = _srs_config->get_http_api_crossdomain();
|
||||
if ((err = conn->set_crossdomain_enabled(v)) != srs_success) {
|
||||
return srs_error_wrap(err, "set cors=%d", v);
|
||||
}
|
||||
|
||||
if ((err = skt->initialize()) != srs_success) {
|
||||
return srs_error_wrap(err, "init socket");
|
||||
}
|
||||
|
||||
return conn->start();
|
||||
}
|
||||
|
||||
string SrsHttpApi::remote_ip()
|
||||
{
|
||||
return conn->remote_ip();
|
||||
}
|
||||
|
||||
const SrsContextId& SrsHttpApi::get_id()
|
||||
{
|
||||
return conn->get_id();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue