正在显示
11 个修改的文件
包含
267 行增加
和
3 行删除
| @@ -109,6 +109,9 @@ http_api { | @@ -109,6 +109,9 @@ http_api { | ||
| 109 | # the http api port | 109 | # the http api port |
| 110 | # default: 1985 | 110 | # default: 1985 |
| 111 | listen 1985; | 111 | listen 1985; |
| 112 | + # whether enable crossdomain request. | ||
| 113 | + # default: on | ||
| 114 | + crossdomain on; | ||
| 112 | } | 115 | } |
| 113 | # embeded http server in srs. | 116 | # embeded http server in srs. |
| 114 | # the http streaming config, for HLS/HDS/DASH/HTTPProgressive | 117 | # the http streaming config, for HLS/HDS/DASH/HTTPProgressive |
| @@ -286,6 +289,31 @@ vhost dvr.srs.com { | @@ -286,6 +289,31 @@ vhost dvr.srs.com { | ||
| 286 | # segment reap flv when flv duration exceed the specified dvr_duration. | 289 | # segment reap flv when flv duration exceed the specified dvr_duration. |
| 287 | # append always append to flv file, never reap it. | 290 | # append always append to flv file, never reap it. |
| 288 | # api reap flv when api required. | 291 | # api reap flv when api required. |
| 292 | + # about the api plan, the HTTP api to dvr, | ||
| 293 | + # http url to control dvr, for example, http://dev:1985/api/v1/dvrs | ||
| 294 | + # method=GET | ||
| 295 | + # to query dvrs of server. | ||
| 296 | + # request params, for example ?vhost=__defaultVhost__, where: | ||
| 297 | + # vhost, query all dvr of this vhost. | ||
| 298 | + # response in json, where: | ||
| 299 | + # {code:0, dvrs: [{plan:"api", path:"./objs/nginx/html", | ||
| 300 | + # autostart:true, wait_keyframe:true, jitter:"full" | ||
| 301 | + # }]} | ||
| 302 | + # method=POST | ||
| 303 | + # to start dvr of specified vhost. | ||
| 304 | + # request should encode in json, specifies the dvr to create, where: | ||
| 305 | + # {plan:"api", path:"./objs/nginx/html", | ||
| 306 | + # autostart:true, wait_keyframe:true, jitter:"full", | ||
| 307 | + # vhost:"__defaultVhost", callback:"http://dvr/callback" | ||
| 308 | + # } | ||
| 309 | + # response in json, where: | ||
| 310 | + # {code:0} | ||
| 311 | + # method=DELETE, to stop dvr | ||
| 312 | + # to stop dvr of specified vhost. | ||
| 313 | + # request params, for example ?vhost=__defaultVhost__, where: | ||
| 314 | + # vhost, stop all dvr of this vhost. | ||
| 315 | + # response in json, where: | ||
| 316 | + # {code:0} | ||
| 289 | # default: session | 317 | # default: session |
| 290 | dvr_plan session; | 318 | dvr_plan session; |
| 291 | # the dvr output path. | 319 | # the dvr output path. |
| @@ -1334,7 +1334,7 @@ int SrsConfig::check_config() | @@ -1334,7 +1334,7 @@ int SrsConfig::check_config() | ||
| 1334 | SrsConfDirective* conf = get_http_api(); | 1334 | SrsConfDirective* conf = get_http_api(); |
| 1335 | for (int i = 0; conf && i < (int)conf->directives.size(); i++) { | 1335 | for (int i = 0; conf && i < (int)conf->directives.size(); i++) { |
| 1336 | string n = conf->at(i)->name; | 1336 | string n = conf->at(i)->name; |
| 1337 | - if (n != "enabled" && n != "listen") { | 1337 | + if (n != "enabled" && n != "listen" && n != "crossdomain") { |
| 1338 | ret = ERROR_SYSTEM_CONFIG_INVALID; | 1338 | ret = ERROR_SYSTEM_CONFIG_INVALID; |
| 1339 | srs_error("unsupported http_api directive %s, ret=%d", n.c_str(), ret); | 1339 | srs_error("unsupported http_api directive %s, ret=%d", n.c_str(), ret); |
| 1340 | return ret; | 1340 | return ret; |
| @@ -3453,6 +3453,22 @@ int SrsConfig::get_http_api_listen() | @@ -3453,6 +3453,22 @@ int SrsConfig::get_http_api_listen() | ||
| 3453 | return ::atoi(conf->arg0().c_str()); | 3453 | return ::atoi(conf->arg0().c_str()); |
| 3454 | } | 3454 | } |
| 3455 | 3455 | ||
| 3456 | +bool SrsConfig::get_http_api_crossdomain() | ||
| 3457 | +{ | ||
| 3458 | + SrsConfDirective* conf = get_http_api(); | ||
| 3459 | + | ||
| 3460 | + if (!conf) { | ||
| 3461 | + return SRS_CONF_DEFAULT_HTTP_API_CROSSDOMAIN; | ||
| 3462 | + } | ||
| 3463 | + | ||
| 3464 | + conf = conf->get("crossdomain"); | ||
| 3465 | + if (!conf || conf->arg0().empty()) { | ||
| 3466 | + return SRS_CONF_DEFAULT_HTTP_API_CROSSDOMAIN; | ||
| 3467 | + } | ||
| 3468 | + | ||
| 3469 | + return conf->arg0() != "off"; | ||
| 3470 | +} | ||
| 3471 | + | ||
| 3456 | bool SrsConfig::get_http_stream_enabled() | 3472 | bool SrsConfig::get_http_stream_enabled() |
| 3457 | { | 3473 | { |
| 3458 | SrsConfDirective* conf = get_http_stream(); | 3474 | SrsConfDirective* conf = get_http_stream(); |
| @@ -79,6 +79,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -79,6 +79,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 79 | 79 | ||
| 80 | #define SRS_CONF_DEFAULT_HTTP_STREAM_PORT 8080 | 80 | #define SRS_CONF_DEFAULT_HTTP_STREAM_PORT 8080 |
| 81 | #define SRS_CONF_DEFAULT_HTTP_API_PORT 1985 | 81 | #define SRS_CONF_DEFAULT_HTTP_API_PORT 1985 |
| 82 | +#define SRS_CONF_DEFAULT_HTTP_API_CROSSDOMAIN true | ||
| 82 | 83 | ||
| 83 | #define SRS_CONF_DEFAULT_HTTP_HEAETBEAT_ENABLED false | 84 | #define SRS_CONF_DEFAULT_HTTP_HEAETBEAT_ENABLED false |
| 84 | #define SRS_CONF_DEFAULT_HTTP_HEAETBEAT_INTERVAL 9.9 | 85 | #define SRS_CONF_DEFAULT_HTTP_HEAETBEAT_INTERVAL 9.9 |
| @@ -957,6 +958,10 @@ public: | @@ -957,6 +958,10 @@ public: | ||
| 957 | * get the http api listen port. | 958 | * get the http api listen port. |
| 958 | */ | 959 | */ |
| 959 | virtual int get_http_api_listen(); | 960 | virtual int get_http_api_listen(); |
| 961 | + /** | ||
| 962 | + * whether enable crossdomain for http api. | ||
| 963 | + */ | ||
| 964 | + virtual bool get_http_api_crossdomain(); | ||
| 960 | // http stream section | 965 | // http stream section |
| 961 | private: | 966 | private: |
| 962 | /** | 967 | /** |
| @@ -40,6 +40,7 @@ using namespace std; | @@ -40,6 +40,7 @@ using namespace std; | ||
| 40 | #include <srs_kernel_file.hpp> | 40 | #include <srs_kernel_file.hpp> |
| 41 | #include <srs_rtmp_amf0.hpp> | 41 | #include <srs_rtmp_amf0.hpp> |
| 42 | #include <srs_kernel_stream.hpp> | 42 | #include <srs_kernel_stream.hpp> |
| 43 | +#include <srs_app_json.hpp> | ||
| 43 | 44 | ||
| 44 | // update the flv duration and filesize every this interval in ms. | 45 | // update the flv duration and filesize every this interval in ms. |
| 45 | #define __SRS_DVR_UPDATE_DURATION_INTERVAL 60000 | 46 | #define __SRS_DVR_UPDATE_DURATION_INTERVAL 60000 |
| @@ -665,6 +666,8 @@ SrsDvrPlan* SrsDvrPlan::create_plan(string vhost) | @@ -665,6 +666,8 @@ SrsDvrPlan* SrsDvrPlan::create_plan(string vhost) | ||
| 665 | return new SrsDvrSessionPlan(); | 666 | return new SrsDvrSessionPlan(); |
| 666 | } else if (plan == SRS_CONF_DEFAULT_DVR_PLAN_APPEND) { | 667 | } else if (plan == SRS_CONF_DEFAULT_DVR_PLAN_APPEND) { |
| 667 | return new SrsDvrAppendPlan(); | 668 | return new SrsDvrAppendPlan(); |
| 669 | + } else if (plan == SRS_CONF_DEFAULT_DVR_PLAN_API) { | ||
| 670 | + return new SrsDvrApiPlan(); | ||
| 668 | } else { | 671 | } else { |
| 669 | srs_error("invalid dvr plan=%s, vhost=%s", plan.c_str(), vhost.c_str()); | 672 | srs_error("invalid dvr plan=%s, vhost=%s", plan.c_str(), vhost.c_str()); |
| 670 | srs_assert(false); | 673 | srs_assert(false); |
| @@ -721,6 +724,56 @@ void SrsDvrSessionPlan::on_unpublish() | @@ -721,6 +724,56 @@ void SrsDvrSessionPlan::on_unpublish() | ||
| 721 | dvr_enabled = false; | 724 | dvr_enabled = false; |
| 722 | } | 725 | } |
| 723 | 726 | ||
| 727 | +SrsDvrApiPlan::SrsDvrApiPlan() | ||
| 728 | +{ | ||
| 729 | +} | ||
| 730 | + | ||
| 731 | +SrsDvrApiPlan::~SrsDvrApiPlan() | ||
| 732 | +{ | ||
| 733 | +} | ||
| 734 | + | ||
| 735 | +int SrsDvrApiPlan::on_publish() | ||
| 736 | +{ | ||
| 737 | + int ret = ERROR_SUCCESS; | ||
| 738 | + | ||
| 739 | + // support multiple publish. | ||
| 740 | + if (dvr_enabled) { | ||
| 741 | + return ret; | ||
| 742 | + } | ||
| 743 | + | ||
| 744 | + if (!_srs_config->get_dvr_enabled(req->vhost)) { | ||
| 745 | + return ret; | ||
| 746 | + } | ||
| 747 | + | ||
| 748 | + if ((ret = segment->close()) != ERROR_SUCCESS) { | ||
| 749 | + return ret; | ||
| 750 | + } | ||
| 751 | + | ||
| 752 | + if ((ret = segment->open()) != ERROR_SUCCESS) { | ||
| 753 | + return ret; | ||
| 754 | + } | ||
| 755 | + | ||
| 756 | + dvr_enabled = true; | ||
| 757 | + | ||
| 758 | + return ret; | ||
| 759 | +} | ||
| 760 | + | ||
| 761 | +void SrsDvrApiPlan::on_unpublish() | ||
| 762 | +{ | ||
| 763 | + // support multiple publish. | ||
| 764 | + if (!dvr_enabled) { | ||
| 765 | + return; | ||
| 766 | + } | ||
| 767 | + | ||
| 768 | + // ignore error. | ||
| 769 | + int ret = segment->close(); | ||
| 770 | + if (ret != ERROR_SUCCESS) { | ||
| 771 | + srs_warn("ignore flv close error. ret=%d", ret); | ||
| 772 | + } | ||
| 773 | + | ||
| 774 | + dvr_enabled = false; | ||
| 775 | +} | ||
| 776 | + | ||
| 724 | SrsDvrAppendPlan::SrsDvrAppendPlan() | 777 | SrsDvrAppendPlan::SrsDvrAppendPlan() |
| 725 | { | 778 | { |
| 726 | last_update_time = 0; | 779 | last_update_time = 0; |
| @@ -977,6 +1030,29 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg) | @@ -977,6 +1030,29 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg) | ||
| 977 | return ret; | 1030 | return ret; |
| 978 | } | 1031 | } |
| 979 | 1032 | ||
| 1033 | +SrsApiDvrPool* SrsApiDvrPool::_instance = new SrsApiDvrPool(); | ||
| 1034 | + | ||
| 1035 | +SrsApiDvrPool* SrsApiDvrPool::instance() | ||
| 1036 | +{ | ||
| 1037 | + return SrsApiDvrPool::_instance; | ||
| 1038 | +} | ||
| 1039 | + | ||
| 1040 | +SrsApiDvrPool::SrsApiDvrPool() | ||
| 1041 | +{ | ||
| 1042 | +} | ||
| 1043 | + | ||
| 1044 | +SrsApiDvrPool::~SrsApiDvrPool() | ||
| 1045 | +{ | ||
| 1046 | +} | ||
| 1047 | + | ||
| 1048 | +int SrsApiDvrPool::dumps(stringstream& ss) | ||
| 1049 | +{ | ||
| 1050 | + int ret = ERROR_SUCCESS; | ||
| 1051 | + ss << __SRS_JARRAY_START | ||
| 1052 | + << __SRS_JARRAY_END; | ||
| 1053 | + return ret; | ||
| 1054 | +} | ||
| 1055 | + | ||
| 980 | SrsDvr::SrsDvr(SrsSource* s) | 1056 | SrsDvr::SrsDvr(SrsSource* s) |
| 981 | { | 1057 | { |
| 982 | source = s; | 1058 | source = s; |
| @@ -30,6 +30,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -30,6 +30,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 30 | #include <srs_core.hpp> | 30 | #include <srs_core.hpp> |
| 31 | 31 | ||
| 32 | #include <string> | 32 | #include <string> |
| 33 | +#include <sstream> | ||
| 33 | 34 | ||
| 34 | #ifdef SRS_AUTO_DVR | 35 | #ifdef SRS_AUTO_DVR |
| 35 | 36 | ||
| @@ -224,6 +225,19 @@ public: | @@ -224,6 +225,19 @@ public: | ||
| 224 | }; | 225 | }; |
| 225 | 226 | ||
| 226 | /** | 227 | /** |
| 228 | +* api plan: reap flv by api. | ||
| 229 | +*/ | ||
| 230 | +class SrsDvrApiPlan : public SrsDvrPlan | ||
| 231 | +{ | ||
| 232 | +public: | ||
| 233 | + SrsDvrApiPlan(); | ||
| 234 | + virtual ~SrsDvrApiPlan(); | ||
| 235 | +public: | ||
| 236 | + virtual int on_publish(); | ||
| 237 | + virtual void on_unpublish(); | ||
| 238 | +}; | ||
| 239 | + | ||
| 240 | +/** | ||
| 227 | * always append to flv file, never reap it. | 241 | * always append to flv file, never reap it. |
| 228 | */ | 242 | */ |
| 229 | class SrsDvrAppendPlan : public SrsDvrPlan | 243 | class SrsDvrAppendPlan : public SrsDvrPlan |
| @@ -283,6 +297,22 @@ private: | @@ -283,6 +297,22 @@ private: | ||
| 283 | }; | 297 | }; |
| 284 | 298 | ||
| 285 | /** | 299 | /** |
| 300 | +* the api dvr pool. | ||
| 301 | +*/ | ||
| 302 | +class SrsApiDvrPool | ||
| 303 | +{ | ||
| 304 | +private: | ||
| 305 | + static SrsApiDvrPool* _instance; | ||
| 306 | +private: | ||
| 307 | + SrsApiDvrPool(); | ||
| 308 | +public: | ||
| 309 | + static SrsApiDvrPool* instance(); | ||
| 310 | + virtual ~SrsApiDvrPool(); | ||
| 311 | +public: | ||
| 312 | + virtual int dumps(std::stringstream& ss); | ||
| 313 | +}; | ||
| 314 | + | ||
| 315 | +/** | ||
| 286 | * dvr(digital video recorder) to record RTMP stream to flv file. | 316 | * dvr(digital video recorder) to record RTMP stream to flv file. |
| 287 | * TODO: FIXME: add utest for it. | 317 | * TODO: FIXME: add utest for it. |
| 288 | */ | 318 | */ |
| @@ -139,6 +139,9 @@ bool srs_go_http_body_allowd(int status) | @@ -139,6 +139,9 @@ bool srs_go_http_body_allowd(int status) | ||
| 139 | // returns "application/octet-stream". | 139 | // returns "application/octet-stream". |
| 140 | string srs_go_http_detect(char* data, int size) | 140 | string srs_go_http_detect(char* data, int size) |
| 141 | { | 141 | { |
| 142 | + // detect only when data specified. | ||
| 143 | + if (data) { | ||
| 144 | + } | ||
| 142 | return "application/octet-stream"; // fallback | 145 | return "application/octet-stream"; // fallback |
| 143 | } | 146 | } |
| 144 | 147 | ||
| @@ -715,8 +718,8 @@ int SrsGoHttpResponseWriter::final_request() | @@ -715,8 +718,8 @@ int SrsGoHttpResponseWriter::final_request() | ||
| 715 | return skt->write((void*)ch.data(), (int)ch.length(), NULL); | 718 | return skt->write((void*)ch.data(), (int)ch.length(), NULL); |
| 716 | } | 719 | } |
| 717 | 720 | ||
| 718 | - // ignore when send with content length | ||
| 719 | - return ERROR_SUCCESS; | 721 | + // flush when send with content length |
| 722 | + return write(NULL, 0); | ||
| 720 | } | 723 | } |
| 721 | 724 | ||
| 722 | SrsGoHttpHeader* SrsGoHttpResponseWriter::header() | 725 | SrsGoHttpHeader* SrsGoHttpResponseWriter::header() |
| @@ -743,6 +746,11 @@ int SrsGoHttpResponseWriter::write(char* data, int size) | @@ -743,6 +746,11 @@ int SrsGoHttpResponseWriter::write(char* data, int size) | ||
| 743 | srs_error("http: send header failed. ret=%d", ret); | 746 | srs_error("http: send header failed. ret=%d", ret); |
| 744 | return ret; | 747 | return ret; |
| 745 | } | 748 | } |
| 749 | + | ||
| 750 | + // ignore NULL content. | ||
| 751 | + if (!data) { | ||
| 752 | + return ret; | ||
| 753 | + } | ||
| 746 | 754 | ||
| 747 | // directly send with content length | 755 | // directly send with content length |
| 748 | if (content_length != -1) { | 756 | if (content_length != -1) { |
| @@ -123,6 +123,29 @@ public: | @@ -123,6 +123,29 @@ public: | ||
| 123 | 123 | ||
| 124 | // A ResponseWriter interface is used by an HTTP handler to | 124 | // A ResponseWriter interface is used by an HTTP handler to |
| 125 | // construct an HTTP response. | 125 | // construct an HTTP response. |
| 126 | +// Usage 1, response with specified length content: | ||
| 127 | +// ISrsGoHttpResponseWriter* w; // create or get response. | ||
| 128 | +// std::string msg = "Hello, HTTP!"; | ||
| 129 | +// w->header()->set_content_type("text/plain; charset=utf-8"); | ||
| 130 | +// w->header()->set_content_length(msg.length()); | ||
| 131 | +// w->write_header(SRS_CONSTS_HTTP_OK); | ||
| 132 | +// w->write((char*)msg.data(), (int)msg.length()); | ||
| 133 | +// w->final_request(); // optional flush. | ||
| 134 | +// Usage 2, response with HTTP code only, zero content length. | ||
| 135 | +// ISrsGoHttpResponseWriter* w; // create or get response. | ||
| 136 | +// w->header()->set_content_length(0); | ||
| 137 | +// w->write_header(SRS_CONSTS_HTTP_OK); | ||
| 138 | +// w->final_request(); | ||
| 139 | +// Usage 3, response in chunked encoding. | ||
| 140 | +// ISrsGoHttpResponseWriter* w; // create or get response. | ||
| 141 | +// std::string msg = "Hello, HTTP!"; | ||
| 142 | +// w->header()->set_content_type("application/octet-stream"); | ||
| 143 | +// w->write_header(SRS_CONSTS_HTTP_OK); | ||
| 144 | +// w->write((char*)msg.data(), (int)msg.length()); | ||
| 145 | +// w->write((char*)msg.data(), (int)msg.length()); | ||
| 146 | +// w->write((char*)msg.data(), (int)msg.length()); | ||
| 147 | +// w->write((char*)msg.data(), (int)msg.length()); | ||
| 148 | +// w->final_request(); // required to end the chunked and flush. | ||
| 126 | class ISrsGoHttpResponseWriter | 149 | class ISrsGoHttpResponseWriter |
| 127 | { | 150 | { |
| 128 | public: | 151 | public: |
| @@ -143,6 +166,7 @@ public: | @@ -143,6 +166,7 @@ public: | ||
| 143 | // before writing the data. If the Header does not contain a | 166 | // before writing the data. If the Header does not contain a |
| 144 | // Content-Type line, Write adds a Content-Type set to the result of passing | 167 | // Content-Type line, Write adds a Content-Type set to the result of passing |
| 145 | // the initial 512 bytes of written data to DetectContentType. | 168 | // the initial 512 bytes of written data to DetectContentType. |
| 169 | + // @param data, the data to send. NULL to flush header only. | ||
| 146 | virtual int write(char* data, int size) = 0; | 170 | virtual int write(char* data, int size) = 0; |
| 147 | 171 | ||
| 148 | // WriteHeader sends an HTTP response header with status code. | 172 | // WriteHeader sends an HTTP response header with status code. |
| @@ -37,6 +37,8 @@ using namespace std; | @@ -37,6 +37,8 @@ using namespace std; | ||
| 37 | #include <srs_app_utility.hpp> | 37 | #include <srs_app_utility.hpp> |
| 38 | #include <srs_app_statistic.hpp> | 38 | #include <srs_app_statistic.hpp> |
| 39 | #include <srs_rtmp_sdk.hpp> | 39 | #include <srs_rtmp_sdk.hpp> |
| 40 | +#include <srs_app_dvr.hpp> | ||
| 41 | +#include <srs_app_config.hpp> | ||
| 40 | 42 | ||
| 41 | SrsGoApiRoot::SrsGoApiRoot() | 43 | SrsGoApiRoot::SrsGoApiRoot() |
| 42 | { | 44 | { |
| @@ -472,11 +474,48 @@ int SrsGoApiStreams::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) | @@ -472,11 +474,48 @@ int SrsGoApiStreams::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) | ||
| 472 | return srs_go_http_response_json(w, ss.str()); | 474 | return srs_go_http_response_json(w, ss.str()); |
| 473 | } | 475 | } |
| 474 | 476 | ||
| 477 | +SrsGoApiDvrs::SrsGoApiDvrs() | ||
| 478 | +{ | ||
| 479 | +} | ||
| 480 | + | ||
| 481 | +SrsGoApiDvrs::~SrsGoApiDvrs() | ||
| 482 | +{ | ||
| 483 | +} | ||
| 484 | + | ||
| 485 | +int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) | ||
| 486 | +{ | ||
| 487 | + std::stringstream ss; | ||
| 488 | + | ||
| 489 | +#ifndef SRS_AUTO_DVR | ||
| 490 | + ss << __SRS_JOBJECT_START | ||
| 491 | + << __SRS_JFIELD_ERROR(ERROR_HTTP_DVR_DISABLED) | ||
| 492 | + << __SRS_JOBJECT_END; | ||
| 493 | +#else | ||
| 494 | + SrsApiDvrPool* pool = SrsApiDvrPool::instance(); | ||
| 495 | + if (r->is_http_get()) { | ||
| 496 | + std::stringstream data; | ||
| 497 | + int ret = pool->dumps(data); | ||
| 498 | + | ||
| 499 | + ss << __SRS_JOBJECT_START | ||
| 500 | + << __SRS_JFIELD_ERROR(ret) << __SRS_JFIELD_CONT | ||
| 501 | + << __SRS_JFIELD_ORG("dvrs", data.str()) | ||
| 502 | + << __SRS_JOBJECT_END; | ||
| 503 | + } else { | ||
| 504 | + ss << __SRS_JOBJECT_START | ||
| 505 | + << __SRS_JFIELD_ERROR(ERROR_HTTP_DVR_REQUEST) | ||
| 506 | + << __SRS_JOBJECT_END; | ||
| 507 | + } | ||
| 508 | +#endif | ||
| 509 | + | ||
| 510 | + return srs_go_http_response_json(w, ss.str()); | ||
| 511 | +} | ||
| 512 | + | ||
| 475 | SrsHttpApi::SrsHttpApi(SrsServer* svr, st_netfd_t fd, SrsGoHttpServeMux* m) | 513 | SrsHttpApi::SrsHttpApi(SrsServer* svr, st_netfd_t fd, SrsGoHttpServeMux* m) |
| 476 | : SrsConnection(svr, fd) | 514 | : SrsConnection(svr, fd) |
| 477 | { | 515 | { |
| 478 | mux = m; | 516 | mux = m; |
| 479 | parser = new SrsHttpParser(); | 517 | parser = new SrsHttpParser(); |
| 518 | + crossdomain_required = false; | ||
| 480 | } | 519 | } |
| 481 | 520 | ||
| 482 | SrsHttpApi::~SrsHttpApi() | 521 | SrsHttpApi::~SrsHttpApi() |
| @@ -549,6 +588,29 @@ int SrsHttpApi::process_request(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) | @@ -549,6 +588,29 @@ int SrsHttpApi::process_request(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) | ||
| 549 | srs_trace("HTTP %s %s, content-length=%"PRId64"", | 588 | srs_trace("HTTP %s %s, content-length=%"PRId64"", |
| 550 | r->method_str().c_str(), r->url().c_str(), r->content_length()); | 589 | r->method_str().c_str(), r->url().c_str(), r->content_length()); |
| 551 | 590 | ||
| 591 | + // method is OPTIONS and enable crossdomain, required crossdomain header. | ||
| 592 | + if (r->is_http_options() && _srs_config->get_http_api_crossdomain()) { | ||
| 593 | + crossdomain_required = true; | ||
| 594 | + } | ||
| 595 | + | ||
| 596 | + // whenever crossdomain required, set crossdomain header. | ||
| 597 | + if (crossdomain_required) { | ||
| 598 | + w->header()->set("Access-Control-Allow-Origin", "*"); | ||
| 599 | + w->header()->set("Access-Control-Allow-Methods", "GET, POST, HEAD, PUT, DELETE"); | ||
| 600 | + w->header()->set("Access-Control-Allow-Headers", "Cache-Control,X-Proxy-Authorization,X-Requested-With,Content-Type"); | ||
| 601 | + } | ||
| 602 | + | ||
| 603 | + // handle the http options. | ||
| 604 | + if (r->is_http_options()) { | ||
| 605 | + w->header()->set_content_length(0); | ||
| 606 | + if (_srs_config->get_http_api_crossdomain()) { | ||
| 607 | + w->write_header(SRS_CONSTS_HTTP_OK); | ||
| 608 | + } else { | ||
| 609 | + w->write_header(SRS_CONSTS_HTTP_MethodNotAllowed); | ||
| 610 | + } | ||
| 611 | + return w->final_request(); | ||
| 612 | + } | ||
| 613 | + | ||
| 552 | // use default server mux to serve http request. | 614 | // use default server mux to serve http request. |
| 553 | if ((ret = mux->serve_http(w, r)) != ERROR_SUCCESS) { | 615 | if ((ret = mux->serve_http(w, r)) != ERROR_SUCCESS) { |
| 554 | if (!srs_is_client_gracefully_close(ret)) { | 616 | if (!srs_is_client_gracefully_close(ret)) { |
| @@ -159,11 +159,21 @@ public: | @@ -159,11 +159,21 @@ public: | ||
| 159 | virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r); | 159 | virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r); |
| 160 | }; | 160 | }; |
| 161 | 161 | ||
| 162 | +class SrsGoApiDvrs : public ISrsGoHttpHandler | ||
| 163 | +{ | ||
| 164 | +public: | ||
| 165 | + SrsGoApiDvrs(); | ||
| 166 | + virtual ~SrsGoApiDvrs(); | ||
| 167 | +public: | ||
| 168 | + virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r); | ||
| 169 | +}; | ||
| 170 | + | ||
| 162 | class SrsHttpApi : public SrsConnection | 171 | class SrsHttpApi : public SrsConnection |
| 163 | { | 172 | { |
| 164 | private: | 173 | private: |
| 165 | SrsHttpParser* parser; | 174 | SrsHttpParser* parser; |
| 166 | SrsGoHttpServeMux* mux; | 175 | SrsGoHttpServeMux* mux; |
| 176 | + bool crossdomain_required; | ||
| 167 | public: | 177 | public: |
| 168 | SrsHttpApi(SrsServer* svr, st_netfd_t fd, SrsGoHttpServeMux* m); | 178 | SrsHttpApi(SrsServer* svr, st_netfd_t fd, SrsGoHttpServeMux* m); |
| 169 | virtual ~SrsHttpApi(); | 179 | virtual ~SrsHttpApi(); |
| @@ -529,6 +529,9 @@ int SrsServer::initialize() | @@ -529,6 +529,9 @@ int SrsServer::initialize() | ||
| 529 | if ((ret = http_api_mux->handle("/api/v1/streams", new SrsGoApiStreams())) != ERROR_SUCCESS) { | 529 | if ((ret = http_api_mux->handle("/api/v1/streams", new SrsGoApiStreams())) != ERROR_SUCCESS) { |
| 530 | return ret; | 530 | return ret; |
| 531 | } | 531 | } |
| 532 | + if ((ret = http_api_mux->handle("/api/v1/dvrs", new SrsGoApiDvrs())) != ERROR_SUCCESS) { | ||
| 533 | + return ret; | ||
| 534 | + } | ||
| 532 | #endif | 535 | #endif |
| 533 | 536 | ||
| 534 | #ifdef SRS_AUTO_HTTP_SERVER | 537 | #ifdef SRS_AUTO_HTTP_SERVER |
| @@ -209,6 +209,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -209,6 +209,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 209 | #define ERROR_AAC_ADTS_HEADER 3047 | 209 | #define ERROR_AAC_ADTS_HEADER 3047 |
| 210 | #define ERROR_AAC_DATA_INVALID 3048 | 210 | #define ERROR_AAC_DATA_INVALID 3048 |
| 211 | #define ERROR_HLS_TRY_MP3 3049 | 211 | #define ERROR_HLS_TRY_MP3 3049 |
| 212 | +#define ERROR_HTTP_DVR_DISABLED 3050 | ||
| 213 | +#define ERROR_HTTP_DVR_REQUEST 3051 | ||
| 212 | 214 | ||
| 213 | /////////////////////////////////////////////////////// | 215 | /////////////////////////////////////////////////////// |
| 214 | // HTTP/StreamCaster protocol error. | 216 | // HTTP/StreamCaster protocol error. |
-
请 注册 或 登录 后发表评论