winlin

support dead-loop detect for forwarder and transcoder.

@@ -97,13 +97,14 @@ Supported operating systems and hardware: @@ -97,13 +97,14 @@ Supported operating systems and hardware:
97 17. support live stream transcoding by ffmpeg.<br/> 97 17. support live stream transcoding by ffmpeg.<br/>
98 18. support ffmpeg filters(logo/overlay/crop), x264 params.<br/> 98 18. support ffmpeg filters(logo/overlay/crop), x264 params.<br/>
99 19. [plan] support network based cli and json result.<br/> 99 19. [plan] support network based cli and json result.<br/>
100 -20. [plan] support bandwidth test api and flash client.<br/>  
101 -21. [plan] support adobe flash refer/token/swf verification.<br/>  
102 -22. [plan] support adobe amf3 codec.<br/>  
103 -23. [plan] support dvr(record live to vod file)<br/>  
104 -24. [plan] support FMS edge protocol<br/>  
105 -25. [plan] support encryption: RTMPE/RTMPS, HLS DRM<br/>  
106 -26. [plan] support RTMPT, http to tranverse firewalls<br/> 100 +20. [plan] support http callback api hooks.<br/>
  101 +21. [plan] support bandwidth test api and flash client.<br/>
  102 +22. [plan] support adobe flash refer/token/swf verification.<br/>
  103 +23. [plan] support adobe amf3 codec.<br/>
  104 +24. [plan] support dvr(record live to vod file)<br/>
  105 +25. [plan] support FMS edge protocol<br/>
  106 +26. [plan] support encryption: RTMPE/RTMPS, HLS DRM<br/>
  107 +27. [plan] support RTMPT, http to tranverse firewalls<br/>
107 108
108 ### Performance 109 ### Performance
109 1. 300 connections, 150Mbps, 500kbps, CPU 18.8%, 5956KB. 110 1. 300 connections, 150Mbps, 500kbps, CPU 18.8%, 5956KB.
@@ -150,8 +151,9 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw @@ -150,8 +151,9 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw
150 * nginx v1.5.0: 139524 lines <br/> 151 * nginx v1.5.0: 139524 lines <br/>
151 152
152 ### History 153 ### History
  154 +* v0.7, 2013-12-01, support dead-loop detect for forwarder and transcoder.
153 * v0.7, 2013-12-01, support all ffmpeg filters and params. 155 * v0.7, 2013-12-01, support all ffmpeg filters and params.
154 -* v0.7, 2013-11-30, support live stream transcoding by ffmpeg. 156 +* v0.7, 2013-11-30, support live stream transcoder by ffmpeg.
155 * v0.7, 2013-11-30, support --with/without -ffmpeg, build ffmpeg-2.1. 157 * v0.7, 2013-11-30, support --with/without -ffmpeg, build ffmpeg-2.1.
156 * v0.7, 2013-11-30, add ffmpeg-2.1, x264-core138, lame-3.99.5, libaacplus-2.0.2. 158 * v0.7, 2013-11-30, add ffmpeg-2.1, x264-core138, lame-3.99.5, libaacplus-2.0.2.
157 * v0.6, 2013-11-29, v0.6 released. 16094 lines. 159 * v0.6, 2013-11-29, v0.6 released. 16094 lines.
@@ -41,7 +41,7 @@ vhost __defaultVhost__ { @@ -41,7 +41,7 @@ vhost __defaultVhost__ {
41 achannels 2; 41 achannels 2;
42 aparams { 42 aparams {
43 } 43 }
44 - output rtmp://[vhost]:[port]/[app]/[stream]_ld; 44 + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
45 } 45 }
46 engine sd{ 46 engine sd{
47 enabled on; 47 enabled on;
@@ -64,7 +64,7 @@ vhost __defaultVhost__ { @@ -64,7 +64,7 @@ vhost __defaultVhost__ {
64 achannels 2; 64 achannels 2;
65 aparams { 65 aparams {
66 } 66 }
67 - output rtmp://[vhost]:[port]/[app]/[stream]_sd; 67 + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
68 } 68 }
69 } 69 }
70 } 70 }
@@ -76,7 +76,7 @@ vhost dev { @@ -76,7 +76,7 @@ vhost dev {
76 hls_path ./objs/nginx/html; 76 hls_path ./objs/nginx/html;
77 hls_fragment 5; 77 hls_fragment 5;
78 hls_window 30; 78 hls_window 30;
79 - #forward dev:19350; 79 + forward 127.0.0.1:19350?vhost=dev;
80 transcode { 80 transcode {
81 enabled on; 81 enabled on;
82 ffmpeg ./objs/ffmpeg/bin/ffmpeg; 82 ffmpeg ./objs/ffmpeg/bin/ffmpeg;
@@ -100,7 +100,7 @@ vhost dev { @@ -100,7 +100,7 @@ vhost dev {
100 achannels 2; 100 achannels 2;
101 aparams { 101 aparams {
102 } 102 }
103 - output rtmp://127.0.0.1:[port]/[app]/[stream]_dev; 103 + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
104 } 104 }
105 } 105 }
106 } 106 }
@@ -130,7 +130,7 @@ vhost mirror.transcode.vhost.com { @@ -130,7 +130,7 @@ vhost mirror.transcode.vhost.com {
130 achannels 2; 130 achannels 2;
131 aparams { 131 aparams {
132 } 132 }
133 - output rtmp://[vhost]:[port]/[app]/[stream]_mirror; 133 + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
134 } 134 }
135 } 135 }
136 } 136 }
@@ -160,7 +160,7 @@ vhost drawtext.transcode.vhost.com { @@ -160,7 +160,7 @@ vhost drawtext.transcode.vhost.com {
160 achannels 2; 160 achannels 2;
161 aparams { 161 aparams {
162 } 162 }
163 - output rtmp://[vhost]:[port]/[app]/[stream]_drawtext; 163 + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
164 } 164 }
165 } 165 }
166 } 166 }
@@ -190,7 +190,7 @@ vhost crop.transcode.vhost.com { @@ -190,7 +190,7 @@ vhost crop.transcode.vhost.com {
190 achannels 2; 190 achannels 2;
191 aparams { 191 aparams {
192 } 192 }
193 - output rtmp://[vhost]:[port]/[app]/[stream]_crop; 193 + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
194 } 194 }
195 } 195 }
196 } 196 }
@@ -220,7 +220,7 @@ vhost logo.transcode.vhost.com { @@ -220,7 +220,7 @@ vhost logo.transcode.vhost.com {
220 achannels 2; 220 achannels 2;
221 aparams { 221 aparams {
222 } 222 }
223 - output rtmp://[vhost]:[port]/[app]/[stream]_logo; 223 + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
224 } 224 }
225 } 225 }
226 } 226 }
@@ -297,7 +297,8 @@ vhost all.transcode.vhost.com { @@ -297,7 +297,8 @@ vhost all.transcode.vhost.com {
297 # [port] the intput stream port. 297 # [port] the intput stream port.
298 # [app] the input stream app. 298 # [app] the input stream app.
299 # [stream] the input stream name. 299 # [stream] the input stream name.
300 - output rtmp://[vhost]:[port]/[app]/[stream]_ffsuper; 300 + # [engine] the tanscode engine name.
  301 + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
301 } 302 }
302 engine ffhd{ 303 engine ffhd{
303 enabled on; 304 enabled on;
@@ -418,15 +419,14 @@ vhost forward.vhost.com { @@ -418,15 +419,14 @@ vhost forward.vhost.com {
418 # this used to split/forward the current stream for cluster active-standby, 419 # this used to split/forward the current stream for cluster active-standby,
419 # active-active for cdn to build high available fault tolerance system. 420 # active-active for cdn to build high available fault tolerance system.
420 # format: {ip}:{port} {ip_N}:{port_N} 421 # format: {ip}:{port} {ip_N}:{port_N}
  422 + # or specify the vhost by:
  423 + # format: {ip}:{port}?vhost={vhost} {ip_N}:{port_N}?vhost={vhost}
  424 + # if vhost not specified, use the request vhost instead.
421 forward 127.0.0.1:1936 127.0.0.1:1937; 425 forward 127.0.0.1:1936 127.0.0.1:1937;
422 } 426 }
423 # the vhost which forward publish streams to other vhosts. 427 # the vhost which forward publish streams to other vhosts.
424 vhost forward1.vhost.com { 428 vhost forward1.vhost.com {
425 - # forward all publish stream to the specified server.  
426 - # this used to split/forward the current stream for cluster active-standby,  
427 - # active-active for cdn to build high available fault tolerance system.  
428 - # format: {ip}:{port} {ip_N}:{port_N}  
429 - forward forward.vhost.com:1936 forward.vhost.com:1937; 429 + forward 127.0.0.1:1936?vhost=forward2.vhost.com 127.0.0.1:1937?vhost=forward3.vhost.com;
430 } 430 }
431 # the vhost disabled. 431 # the vhost disabled.
432 vhost removed.vhost.com { 432 vhost removed.vhost.com {
@@ -24,6 +24,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -24,6 +24,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 #include <srs_core.hpp> 24 #include <srs_core.hpp>
25 25
26 #include <sys/time.h> 26 #include <sys/time.h>
  27 +#include <netdb.h>
  28 +#include <arpa/inet.h>
  29 +
  30 +#include <srs_core_log.hpp>
27 31
28 static int64_t _srs_system_time_us_cache = 0; 32 static int64_t _srs_system_time_us_cache = 0;
29 33
@@ -60,3 +64,49 @@ std::string srs_replace(std::string str, std::string old_str, std::string new_st @@ -60,3 +64,49 @@ std::string srs_replace(std::string str, std::string old_str, std::string new_st
60 64
61 return ret; 65 return ret;
62 } 66 }
  67 +
  68 +std::string srs_dns_resolve(std::string host)
  69 +{
  70 + if (inet_addr(host.c_str()) != INADDR_NONE) {
  71 + return host;
  72 + }
  73 +
  74 + hostent* answer = gethostbyname(host.c_str());
  75 + if (answer == NULL) {
  76 + srs_error("dns resolve host %s error.", host.c_str());
  77 + return "";
  78 + }
  79 +
  80 + char ipv4[16];
  81 + memset(ipv4, 0, sizeof(ipv4));
  82 + for (int i = 0; i < answer->h_length; i++) {
  83 + inet_ntop(AF_INET, answer->h_addr_list[i], ipv4, sizeof(ipv4));
  84 + srs_info("dns resolve host %s to %s.", host.c_str(), ipv4);
  85 + break;
  86 + }
  87 +
  88 + return ipv4;
  89 +}
  90 +
  91 +void srs_vhost_resolve(std::string& vhost, std::string& app)
  92 +{
  93 + app = srs_replace(app, "...", "?");
  94 +
  95 + if ((pos = app.find("?")) == std::string::npos) {
  96 + return;
  97 + }
  98 +
  99 + std::string query = app.substr(pos + 1);
  100 + app = app.substr(0, pos);
  101 +
  102 + if ((pos = query.find("vhost?")) != std::string::npos
  103 + || (pos = query.find("vhost=")) != std::string::npos
  104 + || (pos = query.find("Vhost?")) != std::string::npos
  105 + || (pos = query.find("Vhost=")) != std::string::npos
  106 + ) {
  107 + query = query.substr(pos + 6);
  108 + if (!query.empty()) {
  109 + vhost = query;
  110 + }
  111 + }
  112 +}
@@ -94,5 +94,12 @@ extern void srs_update_system_time_ms(); @@ -94,5 +94,12 @@ extern void srs_update_system_time_ms();
94 #include <string> 94 #include <string>
95 // replace utility 95 // replace utility
96 extern std::string srs_replace(std::string str, std::string old_str, std::string new_str); 96 extern std::string srs_replace(std::string str, std::string old_str, std::string new_str);
  97 +// dns resolve utility, return the resolved ip address.
  98 +extern std::string srs_dns_resolve(std::string host);
  99 +// resolve the vhost in query string
  100 +// @param app, may contains the vhost in query string format:
  101 +// app?vhost=request_vhost
  102 +// app...vhost...request_vhost
  103 +extern void srs_vhost_resolve(std::string& vhost, std::string& app);
97 104
98 #endif 105 #endif
@@ -343,7 +343,7 @@ int SrsClient::publish(SrsSource* source, bool is_fmle) @@ -343,7 +343,7 @@ int SrsClient::publish(SrsSource* source, bool is_fmle)
343 SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER); 343 SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER);
344 344
345 // notify the hls to prepare when publish start. 345 // notify the hls to prepare when publish start.
346 - if ((ret = source->on_publish(req->vhost, req->port, req->app, req->stream)) != ERROR_SUCCESS) { 346 + if ((ret = source->on_publish(req)) != ERROR_SUCCESS) {
347 srs_error("hls on_publish failed. ret=%d", ret); 347 srs_error("hls on_publish failed. ret=%d", ret);
348 return ret; 348 return ret;
349 } 349 }
@@ -37,6 +37,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -37,6 +37,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 // default vhost for rtmp 37 // default vhost for rtmp
38 #define RTMP_VHOST_DEFAULT "__defaultVhost__" 38 #define RTMP_VHOST_DEFAULT "__defaultVhost__"
39 39
  40 +#define SRS_LOCALHOST "127.0.0.1"
  41 +#define RTMP_DEFAULT_PORT 1935
  42 +#define RTMP_DEFAULT_PORTS "1935"
  43 +
40 #define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html" 44 #define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html"
41 #define SRS_CONF_DEFAULT_HLS_FRAGMENT 10 45 #define SRS_CONF_DEFAULT_HLS_FRAGMENT 10
42 #define SRS_CONF_DEFAULT_HLS_WINDOW 60 46 #define SRS_CONF_DEFAULT_HLS_WINDOW 60
@@ -26,15 +26,23 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -26,15 +26,23 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 #include <stdlib.h> 26 #include <stdlib.h>
27 #include <unistd.h> 27 #include <unistd.h>
28 28
  29 +#include <algorithm>
  30 +
29 #include <srs_core_error.hpp> 31 #include <srs_core_error.hpp>
30 #include <srs_core_log.hpp> 32 #include <srs_core_log.hpp>
31 #include <srs_core_config.hpp> 33 #include <srs_core_config.hpp>
  34 +#include <srs_core_rtmp.hpp>
  35 +
  36 +#ifdef SRS_FFMPEG
32 37
33 #define SRS_ENCODER_SLEEP_MS 2000 38 #define SRS_ENCODER_SLEEP_MS 2000
34 39
35 #define SRS_ENCODER_VCODEC "libx264" 40 #define SRS_ENCODER_VCODEC "libx264"
36 #define SRS_ENCODER_ACODEC "libaacplus" 41 #define SRS_ENCODER_ACODEC "libaacplus"
37 42
  43 +// for encoder to detect the dead loop
  44 +static std::vector<std::string> _transcoded_url;
  45 +
38 SrsFFMPEG::SrsFFMPEG(std::string ffmpeg_bin) 46 SrsFFMPEG::SrsFFMPEG(std::string ffmpeg_bin)
39 { 47 {
40 started = false; 48 started = false;
@@ -56,7 +64,7 @@ SrsFFMPEG::~SrsFFMPEG() @@ -56,7 +64,7 @@ SrsFFMPEG::~SrsFFMPEG()
56 stop(); 64 stop();
57 } 65 }
58 66
59 -int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app, std::string stream, SrsConfDirective* engine) 67 +int SrsFFMPEG::initialize(SrsRequest* req, SrsConfDirective* engine)
60 { 68 {
61 int ret = ERROR_SUCCESS; 69 int ret = ERROR_SUCCESS;
62 70
@@ -84,39 +92,32 @@ int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app, @@ -84,39 +92,32 @@ int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app,
84 // input stream, from local. 92 // input stream, from local.
85 // ie. rtmp://127.0.0.1:1935/live/livestream 93 // ie. rtmp://127.0.0.1:1935/live/livestream
86 input = "rtmp://127.0.0.1:"; 94 input = "rtmp://127.0.0.1:";
87 - input += port; 95 + input += req->port;
88 input += "/"; 96 input += "/";
89 - input += app; 97 + input += req->app;
  98 + input += "?vhost=";
  99 + input += req->vhost;
90 input += "/"; 100 input += "/";
91 - input += stream; 101 + input += req->stream;
92 102
93 // output stream, to other/self server 103 // output stream, to other/self server
94 // ie. rtmp://127.0.0.1:1935/live/livestream_sd 104 // ie. rtmp://127.0.0.1:1935/live/livestream_sd
95 - if (vhost == RTMP_VHOST_DEFAULT) {  
96 - output = srs_replace(output, "[vhost]", "127.0.0.1");  
97 - } else {  
98 - output = srs_replace(output, "[vhost]", vhost);  
99 - }  
100 - output = srs_replace(output, "[port]", port);  
101 - output = srs_replace(output, "[app]", app);  
102 - output = srs_replace(output, "[stream]", stream); 105 + output = srs_replace(output, "[vhost]", req->vhost);
  106 + output = srs_replace(output, "[port]", req->port);
  107 + output = srs_replace(output, "[app]", req->app);
  108 + output = srs_replace(output, "[stream]", req->stream);
  109 + output = srs_replace(output, "[engine]", engine->arg0());
103 110
104 // important: loop check, donot transcode again. 111 // important: loop check, donot transcode again.
105 - // we think the following is loop circle:  
106 - // input: rtmp://127.0.0.1:1935/live/livestream_sd  
107 - // output: rtmp://127.0.0.1:1935/live/livestream_sd_sd  
108 - std::string tail = ""; // tail="_sd"  
109 - if (output.length() > input.length()) {  
110 - tail = output.substr(input.length());  
111 - }  
112 - // TODO: better dead loop check.  
113 - // if input also endwiths the tail, loop detected.  
114 - if (!tail.empty() && input.rfind(tail) == input.length() - tail.length()) { 112 + std::vector<std::string>::iterator it;
  113 + it = std::find(_transcoded_url.begin(), _transcoded_url.end(), input);
  114 + if (it != _transcoded_url.end()) {
115 ret = ERROR_ENCODER_LOOP; 115 ret = ERROR_ENCODER_LOOP;
116 srs_info("detect a loop cycle, input=%s, output=%s, ignore it. ret=%d", 116 srs_info("detect a loop cycle, input=%s, output=%s, ignore it. ret=%d",
117 input.c_str(), output.c_str(), ret); 117 input.c_str(), output.c_str(), ret);
118 return ret; 118 return ret;
119 } 119 }
  120 + _transcoded_url.push_back(output);
120 121
121 if (vcodec != SRS_ENCODER_VCODEC) { 122 if (vcodec != SRS_ENCODER_VCODEC) {
122 ret = ERROR_ENCODER_VCODEC; 123 ret = ERROR_ENCODER_VCODEC;
@@ -304,6 +305,20 @@ int SrsFFMPEG::start() @@ -304,6 +305,20 @@ int SrsFFMPEG::start()
304 params.push_back("-y"); 305 params.push_back("-y");
305 params.push_back(output); 306 params.push_back(output);
306 307
  308 + if (true) {
  309 + int pparam_size = 8 * 1024;
  310 + char* pparam = new char[pparam_size];
  311 + char* p = pparam;
  312 + char* last = pparam + pparam_size;
  313 + for (int i = 0; i < (int)params.size(); i++) {
  314 + std::string ffp = params[i];
  315 + snprintf(p, last - p, "%s ", ffp.c_str());
  316 + p += ffp.length() + 1;
  317 + }
  318 + srs_trace("start transcoder: %s", pparam);
  319 + srs_freepa(pparam);
  320 + }
  321 +
307 // TODO: fork or vfork? 322 // TODO: fork or vfork?
308 if ((pid = fork()) < 0) { 323 if ((pid = fork()) < 0) {
309 ret = ERROR_ENCODER_FORK; 324 ret = ERROR_ENCODER_FORK;
@@ -346,6 +361,12 @@ void SrsFFMPEG::stop() @@ -346,6 +361,12 @@ void SrsFFMPEG::stop()
346 if (!started) { 361 if (!started) {
347 return; 362 return;
348 } 363 }
  364 +
  365 + std::vector<std::string>::iterator it;
  366 + it = std::find(_transcoded_url.begin(), _transcoded_url.end(), output);
  367 + if (it != _transcoded_url.end()) {
  368 + _transcoded_url.erase(it);
  369 + }
349 } 370 }
350 371
351 SrsEncoder::SrsEncoder() 372 SrsEncoder::SrsEncoder()
@@ -359,7 +380,7 @@ SrsEncoder::~SrsEncoder() @@ -359,7 +380,7 @@ SrsEncoder::~SrsEncoder()
359 on_unpublish(); 380 on_unpublish();
360 } 381 }
361 382
362 -int SrsEncoder::parse_scope_engines() 383 +int SrsEncoder::parse_scope_engines(SrsRequest* req)
363 { 384 {
364 int ret = ERROR_SUCCESS; 385 int ret = ERROR_SUCCESS;
365 386
@@ -368,17 +389,17 @@ int SrsEncoder::parse_scope_engines() @@ -368,17 +389,17 @@ int SrsEncoder::parse_scope_engines()
368 389
369 // parse vhost scope engines 390 // parse vhost scope engines
370 std::string scope = ""; 391 std::string scope = "";
371 - if ((conf = config->get_transcode(vhost, "")) != NULL) {  
372 - if ((ret = parse_transcode(conf)) != ERROR_SUCCESS) { 392 + if ((conf = config->get_transcode(req->vhost, scope)) != NULL) {
  393 + if ((ret = parse_transcode(req, conf)) != ERROR_SUCCESS) {
373 srs_error("parse vhost scope=%s transcode engines failed. " 394 srs_error("parse vhost scope=%s transcode engines failed. "
374 "ret=%d", scope.c_str(), ret); 395 "ret=%d", scope.c_str(), ret);
375 return ret; 396 return ret;
376 } 397 }
377 } 398 }
378 // parse app scope engines 399 // parse app scope engines
379 - scope = app;  
380 - if ((conf = config->get_transcode(vhost, app)) != NULL) {  
381 - if ((ret = parse_transcode(conf)) != ERROR_SUCCESS) { 400 + scope = req->app;
  401 + if ((conf = config->get_transcode(req->vhost, scope)) != NULL) {
  402 + if ((ret = parse_transcode(req, conf)) != ERROR_SUCCESS) {
382 srs_error("parse app scope=%s transcode engines failed. " 403 srs_error("parse app scope=%s transcode engines failed. "
383 "ret=%d", scope.c_str(), ret); 404 "ret=%d", scope.c_str(), ret);
384 return ret; 405 return ret;
@@ -386,9 +407,9 @@ int SrsEncoder::parse_scope_engines() @@ -386,9 +407,9 @@ int SrsEncoder::parse_scope_engines()
386 } 407 }
387 // parse stream scope engines 408 // parse stream scope engines
388 scope += "/"; 409 scope += "/";
389 - scope += stream;  
390 - if ((conf = config->get_transcode(vhost, app + "/" + stream)) != NULL) {  
391 - if ((ret = parse_transcode(conf)) != ERROR_SUCCESS) { 410 + scope += req->stream;
  411 + if ((conf = config->get_transcode(req->vhost, scope)) != NULL) {
  412 + if ((ret = parse_transcode(req, conf)) != ERROR_SUCCESS) {
392 srs_error("parse stream scope=%s transcode engines failed. " 413 srs_error("parse stream scope=%s transcode engines failed. "
393 "ret=%d", scope.c_str(), ret); 414 "ret=%d", scope.c_str(), ret);
394 return ret; 415 return ret;
@@ -398,16 +419,11 @@ int SrsEncoder::parse_scope_engines() @@ -398,16 +419,11 @@ int SrsEncoder::parse_scope_engines()
398 return ret; 419 return ret;
399 } 420 }
400 421
401 -int SrsEncoder::on_publish(std::string _vhost, std::string _port, std::string _app, std::string _stream) 422 +int SrsEncoder::on_publish(SrsRequest* req)
402 { 423 {
403 int ret = ERROR_SUCCESS; 424 int ret = ERROR_SUCCESS;
404 425
405 - vhost = _vhost;  
406 - port = _port;  
407 - app = _app;  
408 - stream = _stream;  
409 -  
410 - ret = parse_scope_engines(); 426 + ret = parse_scope_engines(req);
411 427
412 // ignore the loop encoder 428 // ignore the loop encoder
413 if (ret == ERROR_ENCODER_LOOP) { 429 if (ret == ERROR_ENCODER_LOOP) {
@@ -457,7 +473,7 @@ SrsFFMPEG* SrsEncoder::at(int index) @@ -457,7 +473,7 @@ SrsFFMPEG* SrsEncoder::at(int index)
457 return ffmpegs[index]; 473 return ffmpegs[index];
458 } 474 }
459 475
460 -int SrsEncoder::parse_transcode(SrsConfDirective* conf) 476 +int SrsEncoder::parse_transcode(SrsRequest* req, SrsConfDirective* conf)
461 { 477 {
462 int ret = ERROR_SUCCESS; 478 int ret = ERROR_SUCCESS;
463 479
@@ -498,7 +514,7 @@ int SrsEncoder::parse_transcode(SrsConfDirective* conf) @@ -498,7 +514,7 @@ int SrsEncoder::parse_transcode(SrsConfDirective* conf)
498 514
499 SrsFFMPEG* ffmpeg = new SrsFFMPEG(ffmpeg_bin); 515 SrsFFMPEG* ffmpeg = new SrsFFMPEG(ffmpeg_bin);
500 516
501 - if ((ret = ffmpeg->initialize(vhost, port, app, stream, engine)) != ERROR_SUCCESS) { 517 + if ((ret = ffmpeg->initialize(req, engine)) != ERROR_SUCCESS) {
502 srs_freep(ffmpeg); 518 srs_freep(ffmpeg);
503 519
504 // if got a loop, donot transcode the whole stream. 520 // if got a loop, donot transcode the whole stream.
@@ -577,3 +593,5 @@ void* SrsEncoder::encoder_thread(void* arg) @@ -577,3 +593,5 @@ void* SrsEncoder::encoder_thread(void* arg)
577 return NULL; 593 return NULL;
578 } 594 }
579 595
  596 +#endif
  597 +
@@ -35,6 +35,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -35,6 +35,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 #include <st.h> 35 #include <st.h>
36 36
37 class SrsConfDirective; 37 class SrsConfDirective;
  38 +class SrsRequest;
  39 +
  40 +#ifdef SRS_FFMPEG
38 41
39 /** 42 /**
40 * a transcode engine: ffmepg, 43 * a transcode engine: ffmepg,
@@ -68,7 +71,7 @@ public: @@ -68,7 +71,7 @@ public:
68 SrsFFMPEG(std::string ffmpeg_bin); 71 SrsFFMPEG(std::string ffmpeg_bin);
69 virtual ~SrsFFMPEG(); 72 virtual ~SrsFFMPEG();
70 public: 73 public:
71 - virtual int initialize(std::string vhost, std::string port, std::string app, std::string stream, SrsConfDirective* engine); 74 + virtual int initialize(SrsRequest* req, SrsConfDirective* engine);
72 virtual int start(); 75 virtual int start();
73 virtual void stop(); 76 virtual void stop();
74 }; 77 };
@@ -80,11 +83,6 @@ public: @@ -80,11 +83,6 @@ public:
80 class SrsEncoder 83 class SrsEncoder
81 { 84 {
82 private: 85 private:
83 - std::string vhost;  
84 - std::string port;  
85 - std::string app;  
86 - std::string stream;  
87 -private:  
88 std::vector<SrsFFMPEG*> ffmpegs; 86 std::vector<SrsFFMPEG*> ffmpegs;
89 private: 87 private:
90 st_thread_t tid; 88 st_thread_t tid;
@@ -93,16 +91,18 @@ public: @@ -93,16 +91,18 @@ public:
93 SrsEncoder(); 91 SrsEncoder();
94 virtual ~SrsEncoder(); 92 virtual ~SrsEncoder();
95 public: 93 public:
96 - virtual int on_publish(std::string vhost, std::string port, std::string app, std::string stream); 94 + virtual int on_publish(SrsRequest* req);
97 virtual void on_unpublish(); 95 virtual void on_unpublish();
98 private: 96 private:
99 - virtual int parse_scope_engines(); 97 + virtual int parse_scope_engines(SrsRequest* req);
100 virtual void clear_engines(); 98 virtual void clear_engines();
101 virtual SrsFFMPEG* at(int index); 99 virtual SrsFFMPEG* at(int index);
102 - virtual int parse_transcode(SrsConfDirective* conf); 100 + virtual int parse_transcode(SrsRequest* req, SrsConfDirective* conf);
103 virtual int cycle(); 101 virtual int cycle();
104 virtual void encoder_cycle(); 102 virtual void encoder_cycle();
105 static void* encoder_thread(void* arg); 103 static void* encoder_thread(void* arg);
106 }; 104 };
107 105
108 #endif 106 #endif
  107 +
  108 +#endif
@@ -85,6 +85,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -85,6 +85,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
85 #define ERROR_SYSTEM_STREAM_BUSY 410 85 #define ERROR_SYSTEM_STREAM_BUSY 410
86 #define ERROR_SYSTEM_IP_INVALID 411 86 #define ERROR_SYSTEM_IP_INVALID 411
87 #define ERROR_SYSTEM_CONFIG_TOO_LARGE 412 87 #define ERROR_SYSTEM_CONFIG_TOO_LARGE 412
  88 +#define ERROR_SYSTEM_FORWARD_LOOP 413
88 89
89 // see librtmp. 90 // see librtmp.
90 // failed when open ssl create the dh 91 // failed when open ssl create the dh
@@ -27,13 +27,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -27,13 +27,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #include <sys/socket.h> 27 #include <sys/socket.h>
28 #include <netinet/in.h> 28 #include <netinet/in.h>
29 #include <arpa/inet.h> 29 #include <arpa/inet.h>
30 -#include <netdb.h>  
31 30
32 #include <srs_core_error.hpp> 31 #include <srs_core_error.hpp>
33 #include <srs_core_rtmp.hpp> 32 #include <srs_core_rtmp.hpp>
34 #include <srs_core_log.hpp> 33 #include <srs_core_log.hpp>
35 #include <srs_core_protocol.hpp> 34 #include <srs_core_protocol.hpp>
36 #include <srs_core_pithy_print.hpp> 35 #include <srs_core_pithy_print.hpp>
  36 +#include <srs_core_rtmp.hpp>
  37 +#include <srs_core_config.hpp>
37 38
38 #define SRS_PULSE_TIMEOUT_MS 100 39 #define SRS_PULSE_TIMEOUT_MS 100
39 #define SRS_FORWARDER_SLEEP_MS 2000 40 #define SRS_FORWARDER_SLEEP_MS 2000
@@ -62,29 +63,54 @@ SrsForwarder::~SrsForwarder() @@ -62,29 +63,54 @@ SrsForwarder::~SrsForwarder()
62 msgs.clear(); 63 msgs.clear();
63 } 64 }
64 65
65 -int SrsForwarder::on_publish(std::string vhost, std::string _app, std::string stream, std::string forward_server) 66 +int SrsForwarder::on_publish(SrsRequest* req, std::string forward_server)
66 { 67 {
67 int ret = ERROR_SUCCESS; 68 int ret = ERROR_SUCCESS;
68 69
69 - app = _app; 70 + // forward app
  71 + app = req->app;
  72 +
  73 + stream_name = req->stream;
  74 + server = forward_server;
  75 + std::string s_port = RTMP_DEFAULT_PORTS;
  76 + port = RTMP_DEFAULT_PORT;
  77 +
  78 + size_t pos = forward_server.find(":");
  79 + if (pos != std::string::npos) {
  80 + s_port = forward_server.substr(pos + 1);
  81 + server = forward_server.substr(0, pos);
  82 + }
  83 + // discovery vhost
  84 + std::string vhost = req->vhost;
  85 + srs_vhost_resolve(vhost, s_port);
  86 + port = ::atoi(s_port.c_str());
70 87
  88 + // generate tcUrl
71 tc_url = "rtmp://"; 89 tc_url = "rtmp://";
72 tc_url += vhost; 90 tc_url += vhost;
73 tc_url += "/"; 91 tc_url += "/";
74 - tc_url += app; 92 + tc_url += req->app;
75 93
76 - stream_name = stream;  
77 - server = forward_server;  
78 - port = 1935; 94 + // dead loop check
  95 + std::string source_ep = req->vhost;
  96 + source_ep += ":";
  97 + source_ep += req->port;
79 98
80 - // TODO: dead loop check. 99 + std::string dest_ep = vhost;
  100 + dest_ep += ":";
  101 + dest_ep += s_port;
81 102
82 - size_t pos = forward_server.find(":");  
83 - if (pos != std::string::npos) {  
84 - port = ::atoi(forward_server.substr(pos + 1).c_str());  
85 - server = forward_server.substr(0, pos); 103 + if (source_ep == dest_ep) {
  104 + ret = ERROR_SYSTEM_FORWARD_LOOP;
  105 + srs_warn("farder loop detected. src=%s, dest=%s, ret=%d",
  106 + source_ep.c_str(), dest_ep.c_str(), ret);
  107 + return ret;
86 } 108 }
  109 + srs_trace("start forward %s to %s, stream: %s/%s",
  110 + source_ep.c_str(), dest_ep.c_str(), tc_url.c_str(),
  111 + stream_name.c_str());
87 112
  113 + // start forward
88 if ((ret = open_socket()) != ERROR_SUCCESS) { 114 if ((ret = open_socket()) != ERROR_SUCCESS) {
89 return ret; 115 return ret;
90 } 116 }
@@ -179,7 +205,7 @@ int SrsForwarder::connect_server() @@ -179,7 +205,7 @@ int SrsForwarder::connect_server()
179 { 205 {
180 int ret = ERROR_SUCCESS; 206 int ret = ERROR_SUCCESS;
181 207
182 - std::string ip = parse_server(server); 208 + std::string ip = srs_dns_resolve(server);
183 if (ip.empty()) { 209 if (ip.empty()) {
184 ret = ERROR_SYSTEM_IP_INVALID; 210 ret = ERROR_SYSTEM_IP_INVALID;
185 srs_error("dns resolve server error, ip empty. ret=%d", ret); 211 srs_error("dns resolve server error, ip empty. ret=%d", ret);
@@ -201,29 +227,6 @@ int SrsForwarder::connect_server() @@ -201,29 +227,6 @@ int SrsForwarder::connect_server()
201 return ret; 227 return ret;
202 } 228 }
203 229
204 -std::string SrsForwarder::parse_server(std::string host)  
205 -{  
206 - if (inet_addr(host.c_str()) != INADDR_NONE) {  
207 - return host;  
208 - }  
209 -  
210 - hostent* answer = gethostbyname(host.c_str());  
211 - if (answer == NULL) {  
212 - srs_error("dns resolve host %s error.", host.c_str());  
213 - return "";  
214 - }  
215 -  
216 - char ipv4[16];  
217 - memset(ipv4, 0, sizeof(ipv4));  
218 - for (int i = 0; i < answer->h_length; i++) {  
219 - inet_ntop(AF_INET, answer->h_addr_list[i], ipv4, sizeof(ipv4));  
220 - srs_info("dns resolve host %s to %s.", host.c_str(), ipv4);  
221 - break;  
222 - }  
223 -  
224 - return ipv4;  
225 -}  
226 -  
227 int SrsForwarder::cycle() 230 int SrsForwarder::cycle()
228 { 231 {
229 int ret = ERROR_SUCCESS; 232 int ret = ERROR_SUCCESS;
@@ -37,6 +37,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -37,6 +37,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 class SrsSharedPtrMessage; 37 class SrsSharedPtrMessage;
38 class SrsOnMetaDataPacket; 38 class SrsOnMetaDataPacket;
39 class SrsRtmpClient; 39 class SrsRtmpClient;
  40 +class SrsRequest;
40 41
41 /** 42 /**
42 * forward the stream to other servers. 43 * forward the stream to other servers.
@@ -61,7 +62,7 @@ public: @@ -61,7 +62,7 @@ public:
61 SrsForwarder(); 62 SrsForwarder();
62 virtual ~SrsForwarder(); 63 virtual ~SrsForwarder();
63 public: 64 public:
64 - virtual int on_publish(std::string vhost, std::string app, std::string stream, std::string forward_server); 65 + virtual int on_publish(SrsRequest* req, std::string forward_server);
65 virtual void on_unpublish(); 66 virtual void on_unpublish();
66 virtual int on_meta_data(SrsSharedPtrMessage* metadata); 67 virtual int on_meta_data(SrsSharedPtrMessage* metadata);
67 virtual int on_audio(SrsSharedPtrMessage* msg); 68 virtual int on_audio(SrsSharedPtrMessage* msg);
@@ -69,7 +70,6 @@ public: @@ -69,7 +70,6 @@ public:
69 private: 70 private:
70 virtual int open_socket(); 71 virtual int open_socket();
71 virtual int connect_server(); 72 virtual int connect_server();
72 - std::string parse_server(std::string host);  
73 private: 73 private:
74 virtual int cycle(); 74 virtual int cycle();
75 virtual int forward(); 75 virtual int forward();
@@ -38,6 +38,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -38,6 +38,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 #include <srs_core_config.hpp> 38 #include <srs_core_config.hpp>
39 #include <srs_core_source.hpp> 39 #include <srs_core_source.hpp>
40 #include <srs_core_autofree.hpp> 40 #include <srs_core_autofree.hpp>
  41 +#include <srs_core_rtmp.hpp>
41 42
42 // @see: NGX_RTMP_HLS_DELAY, 43 // @see: NGX_RTMP_HLS_DELAY,
43 // 63000: 700ms, ts_tbn=90000 44 // 63000: 700ms, ts_tbn=90000
@@ -466,13 +467,13 @@ SrsHls::~SrsHls() @@ -466,13 +467,13 @@ SrsHls::~SrsHls()
466 srs_freep(video_frame); 467 srs_freep(video_frame);
467 } 468 }
468 469
469 -int SrsHls::on_publish(std::string _vhost, std::string _app, std::string _stream) 470 +int SrsHls::on_publish(SrsRequest* req)
470 { 471 {
471 int ret = ERROR_SUCCESS; 472 int ret = ERROR_SUCCESS;
472 473
473 - vhost = _vhost;  
474 - stream = _stream;  
475 - app = _app; 474 + vhost = req->vhost;
  475 + stream = req->stream;
  476 + app = req->app;
476 477
477 // TODO: subscribe the reload event. 478 // TODO: subscribe the reload event.
478 479
@@ -42,6 +42,7 @@ class SrsMpegtsFrame; @@ -42,6 +42,7 @@ class SrsMpegtsFrame;
42 class SrsRtmpJitter; 42 class SrsRtmpJitter;
43 class SrsTSMuxer; 43 class SrsTSMuxer;
44 class SrsCodec; 44 class SrsCodec;
  45 +class SrsRequest;
45 46
46 /** 47 /**
47 * 3.3.2. EXTINF 48 * 3.3.2. EXTINF
@@ -142,7 +143,7 @@ public: @@ -142,7 +143,7 @@ public:
142 SrsHls(); 143 SrsHls();
143 virtual ~SrsHls(); 144 virtual ~SrsHls();
144 public: 145 public:
145 - virtual int on_publish(std::string _vhost, std::string _app, std::string _stream); 146 + virtual int on_publish(SrsRequest* req);
146 virtual void on_unpublish(); 147 virtual void on_unpublish();
147 virtual int on_meta_data(SrsOnMetaDataPacket* metadata); 148 virtual int on_meta_data(SrsOnMetaDataPacket* metadata);
148 virtual int on_audio(SrsSharedPtrMessage* audio); 149 virtual int on_audio(SrsSharedPtrMessage* audio);
@@ -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_autofree.hpp> 30 #include <srs_core_autofree.hpp>
31 #include <srs_core_amf0.hpp> 31 #include <srs_core_amf0.hpp>
32 #include <srs_core_handshake.hpp> 32 #include <srs_core_handshake.hpp>
  33 +#include <srs_core_config.hpp>
33 34
34 /** 35 /**
35 * the signature for packets to client. 36 * the signature for packets to client.
@@ -93,7 +94,7 @@ int SrsRequest::discovery_app() @@ -93,7 +94,7 @@ int SrsRequest::discovery_app()
93 srs_verbose("discovery vhost=%s", vhost.c_str()); 94 srs_verbose("discovery vhost=%s", vhost.c_str());
94 } 95 }
95 96
96 - port = "1935"; 97 + port = RTMP_DEFAULT_PORTS;
97 if ((pos = vhost.find(":")) != std::string::npos) { 98 if ((pos = vhost.find(":")) != std::string::npos) {
98 port = vhost.substr(pos + 1); 99 port = vhost.substr(pos + 1);
99 vhost = vhost.substr(0, pos); 100 vhost = vhost.substr(0, pos);
@@ -101,6 +102,14 @@ int SrsRequest::discovery_app() @@ -101,6 +102,14 @@ int SrsRequest::discovery_app()
101 } 102 }
102 103
103 app = url; 104 app = url;
  105 + srs_vhost_resolve(vhost, app);
  106 +
  107 + // resolve the vhost from config
  108 + SrsConfDirective* parsed_vhost = config->get_vhost(vhost);
  109 + if (parsed_vhost) {
  110 + vhost = parsed_vhost->arg0();
  111 + }
  112 +
104 srs_info("discovery app success. schema=%s, vhost=%s, port=%s, app=%s", 113 srs_info("discovery app success. schema=%s, vhost=%s, port=%s, app=%s",
105 schema.c_str(), vhost.c_str(), port.c_str(), app.c_str()); 114 schema.c_str(), vhost.c_str(), port.c_str(), app.c_str());
106 115
@@ -48,6 +48,12 @@ class SrsOnMetaDataPacket; @@ -48,6 +48,12 @@ class SrsOnMetaDataPacket;
48 */ 48 */
49 struct SrsRequest 49 struct SrsRequest
50 { 50 {
  51 + /**
  52 + * tcUrl: rtmp://request_vhost:port/app/stream
  53 + * support pass vhost in query string, such as:
  54 + * rtmp://ip:port/app?vhost=request_vhost/stream
  55 + * rtmp://ip:port/app...vhost...request_vhost/stream
  56 + */
51 std::string tcUrl; 57 std::string tcUrl;
52 std::string pageUrl; 58 std::string pageUrl;
53 std::string swfUrl; 59 std::string swfUrl;
@@ -34,6 +34,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -34,6 +34,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 #include <srs_core_forward.hpp> 34 #include <srs_core_forward.hpp>
35 #include <srs_core_config.hpp> 35 #include <srs_core_config.hpp>
36 #include <srs_core_encoder.hpp> 36 #include <srs_core_encoder.hpp>
  37 +#include <srs_core_rtmp.hpp>
37 38
38 #define CONST_MAX_JITTER_MS 500 39 #define CONST_MAX_JITTER_MS 500
39 #define DEFAULT_FRAME_TIME_MS 10 40 #define DEFAULT_FRAME_TIME_MS 10
@@ -612,56 +613,48 @@ int SrsSource::on_video(SrsCommonMessage* video) @@ -612,56 +613,48 @@ int SrsSource::on_video(SrsCommonMessage* video)
612 return ret; 613 return ret;
613 } 614 }
614 615
615 -int SrsSource::on_publish(std::string vhost, std::string port, std::string app, std::string stream) 616 +int SrsSource::on_publish(SrsRequest* req)
616 { 617 {
617 int ret = ERROR_SUCCESS; 618 int ret = ERROR_SUCCESS;
618 619
619 _can_publish = false; 620 _can_publish = false;
620 621
621 -#ifdef SRS_HLS  
622 - if ((ret = hls->on_publish(vhost, app, stream)) != ERROR_SUCCESS) {  
623 - return ret;  
624 - }  
625 -#endif  
626 -  
627 -#ifdef SRS_FFMPEG  
628 - if ((ret = encoder->on_publish(vhost, port, app, stream)) != ERROR_SUCCESS) {  
629 - return ret;  
630 - }  
631 -#endif  
632 -  
633 // TODO: support reload. 622 // TODO: support reload.
634 623
635 // create forwarders 624 // create forwarders
636 - SrsConfDirective* conf = config->get_forward(vhost); 625 + SrsConfDirective* conf = config->get_forward(req->vhost);
637 for (int i = 0; conf && i < (int)conf->args.size(); i++) { 626 for (int i = 0; conf && i < (int)conf->args.size(); i++) {
638 std::string forward_server = conf->args.at(i); 627 std::string forward_server = conf->args.at(i);
639 628
640 SrsForwarder* forwarder = new SrsForwarder(); 629 SrsForwarder* forwarder = new SrsForwarder();
641 forwarders.push_back(forwarder); 630 forwarders.push_back(forwarder);
642 631
643 - if ((ret = forwarder->on_publish(vhost, app, stream, forward_server)) != ERROR_SUCCESS) { 632 + if ((ret = forwarder->on_publish(req, forward_server)) != ERROR_SUCCESS) {
644 srs_error("start forwarder failed. " 633 srs_error("start forwarder failed. "
645 "vhost=%s, app=%s, stream=%s, forward-to=%s", 634 "vhost=%s, app=%s, stream=%s, forward-to=%s",
646 - vhost.c_str(), app.c_str(), stream.c_str(), 635 + req->vhost.c_str(), req->app.c_str(), req->stream.c_str(),
647 forward_server.c_str()); 636 forward_server.c_str());
648 return ret; 637 return ret;
649 } 638 }
650 } 639 }
651 640
  641 +#ifdef SRS_FFMPEG
  642 + if ((ret = encoder->on_publish(req)) != ERROR_SUCCESS) {
652 return ret; 643 return ret;
653 -} 644 + }
  645 +#endif
654 646
655 -void SrsSource::on_unpublish()  
656 -{  
657 #ifdef SRS_HLS 647 #ifdef SRS_HLS
658 - hls->on_unpublish(); 648 + if ((ret = hls->on_publish(req)) != ERROR_SUCCESS) {
  649 + return ret;
  650 + }
659 #endif 651 #endif
660 652
661 -#ifdef SRS_FFMPEG  
662 - encoder->on_unpublish();  
663 -#endif 653 + return ret;
  654 +}
664 655
  656 +void SrsSource::on_unpublish()
  657 +{
665 // close all forwarders 658 // close all forwarders
666 std::vector<SrsForwarder*>::iterator it; 659 std::vector<SrsForwarder*>::iterator it;
667 for (it = forwarders.begin(); it != forwarders.end(); ++it) { 660 for (it = forwarders.begin(); it != forwarders.end(); ++it) {
@@ -671,6 +664,14 @@ void SrsSource::on_unpublish() @@ -671,6 +664,14 @@ void SrsSource::on_unpublish()
671 } 664 }
672 forwarders.clear(); 665 forwarders.clear();
673 666
  667 +#ifdef SRS_FFMPEG
  668 + encoder->on_unpublish();
  669 +#endif
  670 +
  671 +#ifdef SRS_HLS
  672 + hls->on_unpublish();
  673 +#endif
  674 +
674 gop_cache->clear(); 675 gop_cache->clear();
675 676
676 srs_freep(cache_metadata); 677 srs_freep(cache_metadata);
@@ -39,6 +39,7 @@ class SrsCommonMessage; @@ -39,6 +39,7 @@ class SrsCommonMessage;
39 class SrsOnMetaDataPacket; 39 class SrsOnMetaDataPacket;
40 class SrsSharedPtrMessage; 40 class SrsSharedPtrMessage;
41 class SrsForwarder; 41 class SrsForwarder;
  42 +class SrsRequest;
42 #ifdef SRS_HLS 43 #ifdef SRS_HLS
43 class SrsHls; 44 class SrsHls;
44 #endif 45 #endif
@@ -210,7 +211,7 @@ public: @@ -210,7 +211,7 @@ public:
210 virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata); 211 virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata);
211 virtual int on_audio(SrsCommonMessage* audio); 212 virtual int on_audio(SrsCommonMessage* audio);
212 virtual int on_video(SrsCommonMessage* video); 213 virtual int on_video(SrsCommonMessage* video);
213 - virtual int on_publish(std::string vhost, std::string port, std::string app, std::string stream); 214 + virtual int on_publish(SrsRequest* req);
214 virtual void on_unpublish(); 215 virtual void on_unpublish();
215 public: 216 public:
216 virtual int create_consumer(SrsConsumer*& consumer); 217 virtual int create_consumer(SrsConsumer*& consumer);