winlin

for #369, support RTMP 302 api at protocol level.

@@ -137,7 +137,7 @@ package @@ -137,7 +137,7 @@ package
137 var ms:NetStream = this.media_stream; 137 var ms:NetStream = this.media_stream;
138 138
139 if (!ms) { 139 if (!ms) {
140 - log("stream is null, ignore timer event."); 140 + //log("stream is null, ignore timer event.");
141 return; 141 return;
142 } 142 }
143 143
@@ -395,6 +395,26 @@ package @@ -395,6 +395,26 @@ package
395 } 395 }
396 update_context_items(); 396 update_context_items();
397 } 397 }
  398 +
  399 + // reject by server, maybe redirect.
  400 + if (evt.info.code == "NetConnection.Connect.Rejected") {
  401 + // RTMP 302 redirect.
  402 + if (evt.info.hasOwnProperty("ex") && evt.info.ex.code == 302) {
  403 + var streamName:String = url.substr(url.lastIndexOf("/") + 1);
  404 + url = evt.info.ex.redirect + "/" + streamName;
  405 + log("Async RTMP 302 Redirect to: " + url);
  406 +
  407 + // notify server.
  408 + media_conn.call("Redirected", null, evt.info.ex.redirect);
  409 +
  410 + // do 302.
  411 + setTimeout(function(){
  412 + log("Async RTMP 302 Redirected.");
  413 + js_call_play(url, _width, _height, buffer_time, max_buffer_time, volume);
  414 + }, 1000);
  415 + return;
  416 + }
  417 + }
398 418
399 // TODO: FIXME: failed event. 419 // TODO: FIXME: failed event.
400 if (evt.info.code != "NetConnection.Connect.Success") { 420 if (evt.info.code != "NetConnection.Connect.Success") {
@@ -26,7 +26,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -26,7 +26,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 bool srs_is_system_control_error(int error_code) 26 bool srs_is_system_control_error(int error_code)
27 { 27 {
28 return error_code == ERROR_CONTROL_RTMP_CLOSE 28 return error_code == ERROR_CONTROL_RTMP_CLOSE
29 - || error_code == ERROR_CONTROL_REPUBLISH; 29 + || error_code == ERROR_CONTROL_REPUBLISH
  30 + || error_code == ERROR_CONTROL_REDIRECT;
30 } 31 }
31 32
32 bool srs_is_client_gracefully_close(int error_code) 33 bool srs_is_client_gracefully_close(int error_code)
@@ -161,6 +161,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -161,6 +161,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
161 // 161 //
162 // system control message, 162 // system control message,
163 // not an error, but special control logic. 163 // not an error, but special control logic.
  164 +//
  165 +// connection is redirect to another server.
  166 +#define ERROR_CONTROL_REDIRECT 2997
164 // sys ctl: rtmp close stream, support replay. 167 // sys ctl: rtmp close stream, support replay.
165 #define ERROR_CONTROL_RTMP_CLOSE 2998 168 #define ERROR_CONTROL_RTMP_CLOSE 2998
166 // FMLE stop publish and republish. 169 // FMLE stop publish and republish.
@@ -306,7 +306,9 @@ string srs_generate_rtmp_url(string server, int port, string vhost, string app, @@ -306,7 +306,9 @@ string srs_generate_rtmp_url(string server, int port, string vhost, string app,
306 ss << "...vhost..." << vhost; 306 ss << "...vhost..." << vhost;
307 } 307 }
308 308
309 - ss << "/" << stream; 309 + if (!stream.empty()) {
  310 + ss << "/" << stream;
  311 + }
310 312
311 return ss.str(); 313 return ss.str();
312 } 314 }
@@ -2575,6 +2575,57 @@ int SrsRtmpServer::response_connect_app(SrsRequest *req, const char* server_ip) @@ -2575,6 +2575,57 @@ int SrsRtmpServer::response_connect_app(SrsRequest *req, const char* server_ip)
2575 return ret; 2575 return ret;
2576 } 2576 }
2577 2577
  2578 +#define SRS_RTMP_REDIRECT_TIMEOUT 3000
  2579 +int SrsRtmpServer::redirect(SrsRequest* r, string host, int port, bool& accepted)
  2580 +{
  2581 + int ret = ERROR_SUCCESS;
  2582 +
  2583 + if (true) {
  2584 + string url = srs_generate_rtmp_url(host, port, r->vhost, r->app, "");
  2585 +
  2586 + SrsAmf0Object* ex = SrsAmf0Any::object();
  2587 + ex->set("code", SrsAmf0Any::number(302));
  2588 + ex->set("redirect", SrsAmf0Any::str(url.c_str()));
  2589 +
  2590 + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();
  2591 +
  2592 + pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelError));
  2593 + pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeConnectRejected));
  2594 + pkt->data->set(StatusDescription, SrsAmf0Any::str("RTMP 302 Redirect"));
  2595 + pkt->data->set("ex", ex);
  2596 +
  2597 + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) {
  2598 + srs_error("send redirect/rejected message failed. ret=%d", ret);
  2599 + return ret;
  2600 + }
  2601 + srs_info("send redirect/rejected message success.");
  2602 + }
  2603 +
  2604 + // client must response a call message.
  2605 + // or we never know whether the client is ok to redirect.
  2606 + protocol->set_recv_timeout(SRS_RTMP_REDIRECT_TIMEOUT * 1000);
  2607 + if (true) {
  2608 + SrsCommonMessage* msg = NULL;
  2609 + SrsCallPacket* pkt = NULL;
  2610 + if ((ret = expect_message<SrsCallPacket>(&msg, &pkt)) != ERROR_SUCCESS) {
  2611 + // ignore any error of redirect response.
  2612 + return ERROR_SUCCESS;
  2613 + }
  2614 + SrsAutoFree(SrsCommonMessage, msg);
  2615 + SrsAutoFree(SrsCallPacket, pkt);
  2616 +
  2617 + string message;
  2618 + if (pkt->arguments && pkt->arguments->is_string()) {
  2619 + message = pkt->arguments->to_str();
  2620 + srs_info("confirm redirected to %s", message.c_str());
  2621 + accepted = true;
  2622 + }
  2623 + srs_info("get redirect response message");
  2624 + }
  2625 +
  2626 + return ret;
  2627 +}
  2628 +
2578 void SrsRtmpServer::response_connect_reject(SrsRequest* /*req*/, const char* desc) 2629 void SrsRtmpServer::response_connect_reject(SrsRequest* /*req*/, const char* desc)
2579 { 2630 {
2580 int ret = ERROR_SUCCESS; 2631 int ret = ERROR_SUCCESS;
@@ -930,6 +930,12 @@ public: @@ -930,6 +930,12 @@ public:
930 */ 930 */
931 virtual int response_connect_app(SrsRequest* req, const char* server_ip = NULL); 931 virtual int response_connect_app(SrsRequest* req, const char* server_ip = NULL);
932 /** 932 /**
  933 + * redirect the connection to another rtmp server.
  934 + * @param the hostname or ip of target.
  935 + * @param whether the client accept the redirect.
  936 + */
  937 + virtual int redirect(SrsRequest* r, std::string host, int port, bool& accepted);
  938 + /**
933 * reject the connect app request. 939 * reject the connect app request.
934 */ 940 */
935 virtual void response_connect_reject(SrsRequest* req, const char* desc); 941 virtual void response_connect_reject(SrsRequest* req, const char* desc);