winlin

implements the proxy for edge publish mode

@@ -41,12 +41,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -41,12 +41,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41 #include <srs_app_source.hpp> 41 #include <srs_app_source.hpp>
42 #include <srs_app_pithy_print.hpp> 42 #include <srs_app_pithy_print.hpp>
43 #include <srs_core_autofree.hpp> 43 #include <srs_core_autofree.hpp>
  44 +#include <srs_app_socket.hpp>
44 45
45 // when error, edge ingester sleep for a while and retry. 46 // when error, edge ingester sleep for a while and retry.
46 #define SRS_EDGE_INGESTER_SLEEP_US (int64_t)(1*1000*1000LL) 47 #define SRS_EDGE_INGESTER_SLEEP_US (int64_t)(1*1000*1000LL)
47 48
48 // when edge timeout, retry next. 49 // when edge timeout, retry next.
49 -#define SRS_EDGE_TIMEOUT_US (int64_t)(3*1000*1000LL) 50 +#define SRS_EDGE_INGESTER_TIMEOUT_US (int64_t)(3*1000*1000LL)
50 51
51 SrsEdgeIngester::SrsEdgeIngester() 52 SrsEdgeIngester::SrsEdgeIngester()
52 { 53 {
@@ -146,7 +147,7 @@ int SrsEdgeIngester::ingest() @@ -146,7 +147,7 @@ int SrsEdgeIngester::ingest()
146 { 147 {
147 int ret = ERROR_SUCCESS; 148 int ret = ERROR_SUCCESS;
148 149
149 - client->set_recv_timeout(SRS_EDGE_TIMEOUT_US); 150 + client->set_recv_timeout(SRS_EDGE_INGESTER_TIMEOUT_US);
150 151
151 SrsPithyPrint pithy_print(SRS_STAGE_EDGE); 152 SrsPithyPrint pithy_print(SRS_STAGE_EDGE);
152 153
@@ -306,6 +307,21 @@ int SrsEdgeIngester::connect_server() @@ -306,6 +307,21 @@ int SrsEdgeIngester::connect_server()
306 return ret; 307 return ret;
307 } 308 }
308 309
  310 +SrsEdgeProxyContext::SrsEdgeProxyContext()
  311 +{
  312 + edge_stream_id = 0;
  313 + edge_io = NULL;
  314 + edge_rtmp = NULL;
  315 +
  316 + origin_stream_id = 0;
  317 + origin_io = NULL;
  318 + origin_rtmp = NULL;
  319 +}
  320 +
  321 +SrsEdgeProxyContext::~SrsEdgeProxyContext()
  322 +{
  323 +}
  324 +
309 SrsEdgeForwarder::SrsEdgeForwarder() 325 SrsEdgeForwarder::SrsEdgeForwarder()
310 { 326 {
311 io = NULL; 327 io = NULL;
@@ -315,14 +331,11 @@ SrsEdgeForwarder::SrsEdgeForwarder() @@ -315,14 +331,11 @@ SrsEdgeForwarder::SrsEdgeForwarder()
315 origin_index = 0; 331 origin_index = 0;
316 stream_id = 0; 332 stream_id = 0;
317 stfd = NULL; 333 stfd = NULL;
318 - pthread = new SrsThread(this, SRS_EDGE_INGESTER_SLEEP_US);  
319 } 334 }
320 335
321 SrsEdgeForwarder::~SrsEdgeForwarder() 336 SrsEdgeForwarder::~SrsEdgeForwarder()
322 { 337 {
323 stop(); 338 stop();
324 -  
325 - srs_freep(pthread);  
326 } 339 }
327 340
328 int SrsEdgeForwarder::initialize(SrsSource* source, SrsPublishEdge* edge, SrsRequest* req) 341 int SrsEdgeForwarder::initialize(SrsSource* source, SrsPublishEdge* edge, SrsRequest* req)
@@ -338,21 +351,6 @@ int SrsEdgeForwarder::initialize(SrsSource* source, SrsPublishEdge* edge, SrsReq @@ -338,21 +351,6 @@ int SrsEdgeForwarder::initialize(SrsSource* source, SrsPublishEdge* edge, SrsReq
338 351
339 int SrsEdgeForwarder::start() 352 int SrsEdgeForwarder::start()
340 { 353 {
341 - return pthread->start();  
342 -}  
343 -  
344 -void SrsEdgeForwarder::stop()  
345 -{  
346 - pthread->stop();  
347 -  
348 - close_underlayer_socket();  
349 -  
350 - srs_freep(client);  
351 - srs_freep(io);  
352 -}  
353 -  
354 -int SrsEdgeForwarder::cycle()  
355 -{  
356 int ret = ERROR_SUCCESS; 354 int ret = ERROR_SUCCESS;
357 355
358 if ((ret = connect_server()) != ERROR_SUCCESS) { 356 if ((ret = connect_server()) != ERROR_SUCCESS) {
@@ -378,37 +376,36 @@ int SrsEdgeForwarder::cycle() @@ -378,37 +376,36 @@ int SrsEdgeForwarder::cycle()
378 return ret; 376 return ret;
379 } 377 }
380 378
381 - if ((ret = client->play(req->stream, stream_id)) != ERROR_SUCCESS) { 379 + if ((ret = client->publish(req->stream, stream_id)) != ERROR_SUCCESS) {
382 srs_error("connect with server failed, stream=%s, stream_id=%d. ret=%d", 380 srs_error("connect with server failed, stream=%s, stream_id=%d. ret=%d",
383 req->stream.c_str(), stream_id, ret); 381 req->stream.c_str(), stream_id, ret);
384 return ret; 382 return ret;
385 } 383 }
386 384
387 - if ((ret = _source->on_publish()) != ERROR_SUCCESS) {  
388 - srs_error("edge ingester play stream then publish to edge failed. ret=%d", ret);  
389 - return ret;  
390 - }  
391 -  
392 - if ((ret = _edge->on_forward_publish()) != ERROR_SUCCESS) {  
393 - return ret;  
394 - }  
395 -  
396 - if ((ret = forward()) != ERROR_SUCCESS) {  
397 - return ret;  
398 - }  
399 -  
400 return ret; 385 return ret;
401 } 386 }
402 387
403 -int SrsEdgeForwarder::forward() 388 +void SrsEdgeForwarder::stop()
  389 +{
  390 + close_underlayer_socket();
  391 +
  392 + srs_freep(client);
  393 + srs_freep(io);
  394 +}
  395 +
  396 +int SrsEdgeForwarder::proxy(SrsEdgeProxyContext* context)
404 { 397 {
405 int ret = ERROR_SUCCESS; 398 int ret = ERROR_SUCCESS;
406 399
407 - client->set_recv_timeout(SRS_EDGE_TIMEOUT_US); 400 + context->origin_io = io;
  401 + context->origin_rtmp = client;
  402 + context->origin_stream_id = stream_id;
  403 +
  404 + client->set_recv_timeout(SRS_PULSE_TIMEOUT_US);
408 405
409 SrsPithyPrint pithy_print(SRS_STAGE_EDGE); 406 SrsPithyPrint pithy_print(SRS_STAGE_EDGE);
410 407
411 - while (pthread->can_loop()) { 408 + while (true) {
412 // switch to other st-threads. 409 // switch to other st-threads.
413 st_usleep(0); 410 st_usleep(0);
414 411
@@ -419,17 +416,59 @@ int SrsEdgeForwarder::forward() @@ -419,17 +416,59 @@ int SrsEdgeForwarder::forward()
419 srs_trace("<- time=%"PRId64", obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d", 416 srs_trace("<- time=%"PRId64", obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d",
420 pithy_print.age(), client->get_send_bytes(), client->get_recv_bytes(), client->get_send_kbps(), client->get_recv_kbps()); 417 pithy_print.age(), client->get_send_bytes(), client->get_recv_bytes(), client->get_send_kbps(), client->get_recv_kbps());
421 } 418 }
422 -  
423 - // read from client.  
424 - SrsCommonMessage* msg = NULL;  
425 - if ((ret = client->recv_message(&msg)) != ERROR_SUCCESS) {  
426 - srs_error("recv origin server message failed. ret=%d", ret); 419 +
  420 + if ((ret = proxy_message(context)) != ERROR_SUCCESS) {
427 return ret; 421 return ret;
428 } 422 }
429 - srs_verbose("edge loop recv message. ret=%d", ret);  
430 -  
431 - srs_assert(msg);  
432 - SrsAutoFree(SrsCommonMessage, msg, false); 423 + }
  424 +
  425 + return ret;
  426 +}
  427 +
  428 +int SrsEdgeForwarder::proxy_message(SrsEdgeProxyContext* context)
  429 +{
  430 + int ret = ERROR_SUCCESS;
  431 +
  432 + SrsCommonMessage* msg = NULL;
  433 +
  434 + // proxy origin message to client
  435 + msg = NULL;
  436 + ret = context->origin_rtmp->recv_message(&msg);
  437 + if (ret != ERROR_SUCCESS && ret != ERROR_SOCKET_TIMEOUT) {
  438 + srs_error("recv origin server message failed. ret=%d", ret);
  439 + return ret;
  440 + }
  441 +
  442 + if (msg) {
  443 + if (msg->size <= 0) {
  444 + srs_freep(msg);
  445 + } else {
  446 + msg->header.stream_id = context->edge_stream_id;
  447 + if ((ret = context->edge_rtmp->send_message(msg)) != ERROR_SUCCESS) {
  448 + srs_error("send origin message to client failed. ret=%d", ret);
  449 + return ret;
  450 + }
  451 + }
  452 + }
  453 +
  454 + // proxy client message to origin
  455 + msg = NULL;
  456 + ret = context->edge_rtmp->recv_message(&msg);
  457 + if (ret != ERROR_SUCCESS && ret != ERROR_SOCKET_TIMEOUT) {
  458 + srs_error("recv client message failed. ret=%d", ret);
  459 + return ret;
  460 + }
  461 +
  462 + if (msg) {
  463 + if (msg->size <= 0) {
  464 + srs_freep(msg);
  465 + } else {
  466 + msg->header.stream_id = context->origin_stream_id;
  467 + if ((ret = context->origin_rtmp->send_message(msg)) != ERROR_SUCCESS) {
  468 + srs_error("send client message to origin failed. ret=%d", ret);
  469 + return ret;
  470 + }
  471 + }
433 } 472 }
434 473
435 return ret; 474 return ret;
@@ -620,21 +659,33 @@ int SrsPublishEdge::on_client_publish() @@ -620,21 +659,33 @@ int SrsPublishEdge::on_client_publish()
620 // error state. 659 // error state.
621 if (user_state != SrsEdgeUserStateInit) { 660 if (user_state != SrsEdgeUserStateInit) {
622 ret = ERROR_RTMP_EDGE_PUBLISH_STATE; 661 ret = ERROR_RTMP_EDGE_PUBLISH_STATE;
623 - srs_error("invalid state for client to play stream on edge. " 662 + srs_error("invalid state for client to publish stream on edge. "
624 "state=%d, user_state=%d, ret=%d", state, user_state, ret); 663 "state=%d, user_state=%d, ret=%d", state, user_state, ret);
625 return ret; 664 return ret;
626 } 665 }
627 666
628 - // start ingest when init state.  
629 - if (state == SrsEdgeStateInit) {  
630 - state = SrsEdgeStatePublish; 667 + // error when not init state.
  668 + if (state != SrsEdgeStateInit) {
  669 + ret = ERROR_RTMP_EDGE_PUBLISH_STATE;
  670 + srs_error("invalid state for client to publish stream on edge. "
  671 + "state=%d, user_state=%d, ret=%d", state, user_state, ret);
  672 + return ret;
631 } 673 }
632 -  
633 - return ret; 674 +
  675 + SrsEdgeState pstate = state;
  676 + state = SrsEdgeStatePublish;
  677 + srs_trace("edge change from %d to state %d (forward publish).", pstate, state);
  678 +
  679 + return forwarder->start();
634 } 680 }
635 681
636 -int SrsPublishEdge::on_forward_publish() 682 +int SrsPublishEdge::on_proxy_publish(SrsEdgeProxyContext* context)
637 { 683 {
638 - int ret = ERROR_SUCCESS; 684 + int ret = forwarder->proxy(context);
  685 +
  686 + SrsEdgeState pstate = state;
  687 + state = SrsEdgeStateInit;
  688 + srs_trace("edge change from %d to state %d (init).", pstate, state);
  689 +
639 return ret; 690 return ret;
640 } 691 }
@@ -33,6 +33,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -33,6 +33,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 #include <srs_app_st.hpp> 33 #include <srs_app_st.hpp>
34 #include <srs_app_thread.hpp> 34 #include <srs_app_thread.hpp>
35 35
  36 +class SrsSocket;
  37 +class SrsRtmpServer;
36 class SrsSource; 38 class SrsSource;
37 class SrsRequest; 39 class SrsRequest;
38 class SrsPlayEdge; 40 class SrsPlayEdge;
@@ -55,8 +57,6 @@ enum SrsEdgeState @@ -55,8 +57,6 @@ enum SrsEdgeState
55 57
56 // for publish edge 58 // for publish edge
57 SrsEdgeStatePublish = 200, 59 SrsEdgeStatePublish = 200,
58 - // publish stream to edge, forward to origin  
59 - SrsEdgeStateForwardConnected,  
60 }; 60 };
61 61
62 /** 62 /**
@@ -101,10 +101,25 @@ private: @@ -101,10 +101,25 @@ private:
101 virtual int process_publish_message(SrsCommonMessage* msg); 101 virtual int process_publish_message(SrsCommonMessage* msg);
102 }; 102 };
103 103
  104 +class SrsEdgeProxyContext
  105 +{
  106 +public:
  107 + int edge_stream_id;
  108 + ISrsProtocolReaderWriter* edge_io;
  109 + SrsRtmpServer* edge_rtmp;
  110 +public:
  111 + int origin_stream_id;
  112 + ISrsProtocolReaderWriter* origin_io;
  113 + SrsRtmpClient* origin_rtmp;
  114 +public:
  115 + SrsEdgeProxyContext();
  116 + virtual ~SrsEdgeProxyContext();
  117 +};
  118 +
104 /** 119 /**
105 * edge used to forward stream to origin. 120 * edge used to forward stream to origin.
106 */ 121 */
107 -class SrsEdgeForwarder : public ISrsThreadHandler 122 +class SrsEdgeForwarder
108 { 123 {
109 private: 124 private:
110 int stream_id; 125 int stream_id;
@@ -112,7 +127,6 @@ private: @@ -112,7 +127,6 @@ private:
112 SrsSource* _source; 127 SrsSource* _source;
113 SrsPublishEdge* _edge; 128 SrsPublishEdge* _edge;
114 SrsRequest* _req; 129 SrsRequest* _req;
115 - SrsThread* pthread;  
116 st_netfd_t stfd; 130 st_netfd_t stfd;
117 ISrsProtocolReaderWriter* io; 131 ISrsProtocolReaderWriter* io;
118 SrsRtmpClient* client; 132 SrsRtmpClient* client;
@@ -124,11 +138,10 @@ public: @@ -124,11 +138,10 @@ public:
124 virtual int initialize(SrsSource* source, SrsPublishEdge* edge, SrsRequest* req); 138 virtual int initialize(SrsSource* source, SrsPublishEdge* edge, SrsRequest* req);
125 virtual int start(); 139 virtual int start();
126 virtual void stop(); 140 virtual void stop();
127 -// interface ISrsThreadHandler  
128 public: 141 public:
129 - virtual int cycle(); 142 + virtual int proxy(SrsEdgeProxyContext* context);
130 private: 143 private:
131 - virtual int forward(); 144 + virtual int proxy_message(SrsEdgeProxyContext* context);
132 virtual void close_underlayer_socket(); 145 virtual void close_underlayer_socket();
133 virtual int connect_server(); 146 virtual int connect_server();
134 }; 147 };
@@ -182,11 +195,10 @@ public: @@ -182,11 +195,10 @@ public:
182 * when client publish stream on edge. 195 * when client publish stream on edge.
183 */ 196 */
184 virtual int on_client_publish(); 197 virtual int on_client_publish();
185 -public:  
186 /** 198 /**
187 - * when forwarder start to publish stream. 199 + * proxy publish stream to edge
188 */ 200 */
189 - virtual int on_forward_publish(); 201 + virtual int on_proxy_publish(SrsEdgeProxyContext* context);
190 }; 202 };
191 203
192 #endif 204 #endif
@@ -42,6 +42,7 @@ using namespace std; @@ -42,6 +42,7 @@ using namespace std;
42 #include <srs_app_bandwidth.hpp> 42 #include <srs_app_bandwidth.hpp>
43 #include <srs_app_socket.hpp> 43 #include <srs_app_socket.hpp>
44 #include <srs_app_http_hooks.hpp> 44 #include <srs_app_http_hooks.hpp>
  45 +#include <srs_app_edge.hpp>
45 46
46 // when stream is busy, for example, streaming is already 47 // when stream is busy, for example, streaming is already
47 // publishing, when a new client to request to publish, 48 // publishing, when a new client to request to publish,
@@ -332,6 +333,15 @@ int SrsRtmpConn::stream_service_cycle() @@ -332,6 +333,15 @@ int SrsRtmpConn::stream_service_cycle()
332 srs_error("start to publish stream failed. ret=%d", ret); 333 srs_error("start to publish stream failed. ret=%d", ret);
333 return ret; 334 return ret;
334 } 335 }
  336 +
  337 + SrsEdgeProxyContext context;
  338 + context.edge_io = skt;
  339 + context.edge_stream_id = res->stream_id;
  340 + context.edge_rtmp = rtmp;
  341 + if (vhost_is_edge) {
  342 + return source->on_edge_proxy_publish(&context);
  343 + }
  344 +
335 if ((ret = on_publish()) != ERROR_SUCCESS) { 345 if ((ret = on_publish()) != ERROR_SUCCESS) {
336 srs_error("http hook on_publish failed. ret=%d", ret); 346 srs_error("http hook on_publish failed. ret=%d", ret);
337 return ret; 347 return ret;
@@ -345,10 +355,26 @@ int SrsRtmpConn::stream_service_cycle() @@ -345,10 +355,26 @@ int SrsRtmpConn::stream_service_cycle()
345 case SrsRtmpConnFlashPublish: { 355 case SrsRtmpConnFlashPublish: {
346 srs_verbose("flash start to publish stream %s.", req->stream.c_str()); 356 srs_verbose("flash start to publish stream %s.", req->stream.c_str());
347 357
  358 + if (vhost_is_edge) {
  359 + if ((ret = source->on_edge_start_publish()) != ERROR_SUCCESS) {
  360 + srs_error("notice edge start publish stream failed. ret=%d", ret);
  361 + return ret;
  362 + }
  363 + }
  364 +
348 if ((ret = rtmp->start_flash_publish(res->stream_id)) != ERROR_SUCCESS) { 365 if ((ret = rtmp->start_flash_publish(res->stream_id)) != ERROR_SUCCESS) {
349 srs_error("flash start to publish stream failed. ret=%d", ret); 366 srs_error("flash start to publish stream failed. ret=%d", ret);
350 return ret; 367 return ret;
351 } 368 }
  369 +
  370 + SrsEdgeProxyContext context;
  371 + context.edge_io = skt;
  372 + context.edge_stream_id = res->stream_id;
  373 + context.edge_rtmp = rtmp;
  374 + if (vhost_is_edge) {
  375 + return source->on_edge_proxy_publish(&context);
  376 + }
  377 +
352 if ((ret = on_publish()) != ERROR_SUCCESS) { 378 if ((ret = on_publish()) != ERROR_SUCCESS) {
353 srs_error("http hook on_publish failed. ret=%d", ret); 379 srs_error("http hook on_publish failed. ret=%d", ret);
354 return ret; 380 return ret;
@@ -1199,6 +1199,11 @@ int SrsSource::on_edge_start_publish() @@ -1199,6 +1199,11 @@ int SrsSource::on_edge_start_publish()
1199 return publish_edge->on_client_publish(); 1199 return publish_edge->on_client_publish();
1200 } 1200 }
1201 1201
  1202 +int SrsSource::on_edge_proxy_publish(SrsEdgeProxyContext* context)
  1203 +{
  1204 + return publish_edge->on_proxy_publish(context);
  1205 +}
  1206 +
1202 int SrsSource::create_forwarders() 1207 int SrsSource::create_forwarders()
1203 { 1208 {
1204 int ret = ERROR_SUCCESS; 1209 int ret = ERROR_SUCCESS;
@@ -45,6 +45,9 @@ class SrsOnMetaDataPacket; @@ -45,6 +45,9 @@ class SrsOnMetaDataPacket;
45 class SrsSharedPtrMessage; 45 class SrsSharedPtrMessage;
46 class SrsForwarder; 46 class SrsForwarder;
47 class SrsRequest; 47 class SrsRequest;
  48 +class SrsSocket;
  49 +class SrsRtmpServer;
  50 +class SrsEdgeProxyContext;
48 #ifdef SRS_AUTO_HLS 51 #ifdef SRS_AUTO_HLS
49 class SrsHls; 52 class SrsHls;
50 #endif 53 #endif
@@ -318,6 +321,8 @@ public: @@ -318,6 +321,8 @@ public:
318 virtual int on_edge_start_play(); 321 virtual int on_edge_start_play();
319 // for edge, when publish edge stream, check the state 322 // for edge, when publish edge stream, check the state
320 virtual int on_edge_start_publish(); 323 virtual int on_edge_start_publish();
  324 + // for edge, proxy the publish
  325 + virtual int on_edge_proxy_publish(SrsEdgeProxyContext* context);
321 private: 326 private:
322 virtual int create_forwarders(); 327 virtual int create_forwarders();
323 virtual void destroy_forwarders(); 328 virtual void destroy_forwarders();
@@ -652,11 +652,17 @@ int SrsProtocol::on_send_message(ISrsMessage* msg) @@ -652,11 +652,17 @@ int SrsProtocol::on_send_message(ISrsMessage* msg)
652 } 652 }
653 653
654 SrsCommonMessage* common_msg = dynamic_cast<SrsCommonMessage*>(msg); 654 SrsCommonMessage* common_msg = dynamic_cast<SrsCommonMessage*>(msg);
655 - if (!msg) { 655 + if (!common_msg) {
656 srs_verbose("ignore the shared ptr message."); 656 srs_verbose("ignore the shared ptr message.");
657 return ret; 657 return ret;
658 } 658 }
659 659
  660 + // for proxy, the common msg is not decoded, ignore.
  661 + if (!common_msg->has_packet()) {
  662 + srs_verbose("ignore the proxy common message.");
  663 + return ret;
  664 + }
  665 +
660 srs_assert(common_msg != NULL); 666 srs_assert(common_msg != NULL);
661 667
662 switch (common_msg->header.message_type) { 668 switch (common_msg->header.message_type) {
@@ -1459,6 +1465,11 @@ int SrsCommonMessage::decode_packet(SrsProtocol* protocol) @@ -1459,6 +1465,11 @@ int SrsCommonMessage::decode_packet(SrsProtocol* protocol)
1459 return ret; 1465 return ret;
1460 } 1466 }
1461 1467
  1468 +bool SrsCommonMessage::has_packet()
  1469 +{
  1470 + return packet != NULL;
  1471 +}
  1472 +
1462 SrsPacket* SrsCommonMessage::get_packet() 1473 SrsPacket* SrsCommonMessage::get_packet()
1463 { 1474 {
1464 if (!packet) { 1475 if (!packet) {
@@ -1501,6 +1512,14 @@ int SrsCommonMessage::encode_packet() @@ -1501,6 +1512,14 @@ int SrsCommonMessage::encode_packet()
1501 { 1512 {
1502 int ret = ERROR_SUCCESS; 1513 int ret = ERROR_SUCCESS;
1503 1514
  1515 + // sometimes, for example, the edge proxy,
  1516 + // the payload is not decoded, so directly sent out.
  1517 + if (payload != NULL) {
  1518 + header.payload_length = size;
  1519 + return ret;
  1520 + }
  1521 +
  1522 + // encode packet to payload and size.
1504 if (packet == NULL) { 1523 if (packet == NULL) {
1505 srs_warn("packet is empty, send out empty message."); 1524 srs_warn("packet is empty, send out empty message.");
1506 return ret; 1525 return ret;
@@ -352,6 +352,10 @@ public: @@ -352,6 +352,10 @@ public:
352 // TODO: use protocol to decode it. 352 // TODO: use protocol to decode it.
353 virtual int decode_packet(SrsProtocol* protocol); 353 virtual int decode_packet(SrsProtocol* protocol);
354 /** 354 /**
  355 + * whether msg has decoded packet.
  356 + */
  357 + virtual bool has_packet();
  358 + /**
355 * get the decoded packet which decoded by decode_packet(). 359 * get the decoded packet which decoded by decode_packet().
356 * @remark, user never free the pkt, the message will auto free it. 360 * @remark, user never free the pkt, the message will auto free it.
357 */ 361 */