1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-02-24 06:54:22 +00:00
srs/trunk/src/app/srs_app_edge.cpp

781 lines
21 KiB
C++
Raw Normal View History

2017-03-25 09:21:39 +00:00
/**
* The MIT License (MIT)
*
2019-01-01 13:37:28 +00:00
* Copyright (c) 2013-2019 Winlin
2017-03-25 09:21:39 +00:00
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
2014-04-25 08:35:03 +00:00
#include <srs_app_edge.hpp>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;
#include <srs_kernel_error.hpp>
2015-06-13 08:04:59 +00:00
#include <srs_rtmp_stack.hpp>
2015-09-22 01:07:07 +00:00
#include <srs_protocol_io.hpp>
#include <srs_app_config.hpp>
#include <srs_protocol_utility.hpp>
2015-06-14 00:43:38 +00:00
#include <srs_app_st.hpp>
#include <srs_app_source.hpp>
#include <srs_app_pithy_print.hpp>
#include <srs_core_autofree.hpp>
2015-05-23 01:58:00 +00:00
#include <srs_protocol_kbps.hpp>
2015-01-23 02:07:20 +00:00
#include <srs_rtmp_msg_array.hpp>
#include <srs_app_utility.hpp>
2015-09-22 01:05:21 +00:00
#include <srs_protocol_amf0.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_kernel_balance.hpp>
2015-10-14 06:37:24 +00:00
#include <srs_app_rtmp_conn.hpp>
2014-04-26 10:08:21 +00:00
// when edge timeout, retry next.
2019-04-07 08:25:52 +00:00
#define SRS_EDGE_INGESTER_TMMS (5 * SRS_UTIME_MILLISECONDS)
2014-04-26 10:08:21 +00:00
2014-04-28 09:20:35 +00:00
// when edge error, wait for quit
2019-04-07 08:25:52 +00:00
#define SRS_EDGE_FORWARDER_TMMS (150 * SRS_UTIME_MILLISECONDS)
2014-04-28 09:20:35 +00:00
SrsEdgeUpstream::SrsEdgeUpstream()
{
}
SrsEdgeUpstream::~SrsEdgeUpstream()
{
}
2016-01-11 07:46:23 +00:00
SrsEdgeRtmpUpstream::SrsEdgeRtmpUpstream(string r)
{
2016-01-11 07:46:23 +00:00
redirect = r;
sdk = NULL;
}
SrsEdgeRtmpUpstream::~SrsEdgeRtmpUpstream()
{
close();
}
2018-01-01 11:39:57 +00:00
srs_error_t SrsEdgeRtmpUpstream::connect(SrsRequest* r, SrsLbRoundRobin* lb)
{
2018-01-01 11:39:57 +00:00
srs_error_t err = srs_success;
SrsRequest* req = r;
std::string url;
if (true) {
SrsConfDirective* conf = _srs_config->get_vhost_edge_origin(req->vhost);
// @see https://github.com/ossrs/srs/issues/79
// when origin is error, for instance, server is shutdown,
// then user remove the vhost then reload, the conf is empty.
if (!conf) {
2018-01-01 11:39:57 +00:00
return srs_error_new(ERROR_EDGE_VHOST_REMOVED, "vhost %s removed", req->vhost.c_str());
}
// select the origin.
std::string server = lb->select(conf->args);
int port = SRS_CONSTS_RTMP_DEFAULT_PORT;
srs_parse_hostport(server, server, port);
2016-01-11 07:46:23 +00:00
// override the origin info by redirect.
if (!redirect.empty()) {
int _port;
string _schema, _vhost, _app, _stream, _param, _host;
srs_discovery_tc_url(redirect, _schema, _host, _vhost, _app, _stream, _port, _param);
2016-01-11 07:46:23 +00:00
srs_warn("RTMP redirect %s:%d to %s:%d stream=%s", server.c_str(), port, _host.c_str(), _port, _stream.c_str());
2016-01-11 07:46:23 +00:00
server = _host;
port = _port;
}
// support vhost tranform for edge,
// @see https://github.com/ossrs/srs/issues/372
std::string vhost = _srs_config->get_vhost_edge_transform_vhost(req->vhost);
vhost = srs_string_replace(vhost, "[vhost]", req->vhost);
url = srs_generate_rtmp_url(server, port, req->host, vhost, req->app, req->stream, req->param);
}
srs_freep(sdk);
int64_t cto = srsu2ms(SRS_EDGE_INGESTER_TMMS);
int64_t sto = SRS_CONSTS_RTMP_PULSE_TMMS;
sdk = new SrsSimpleRtmpClient(url, cto, sto);
2018-01-01 11:39:57 +00:00
if ((err = sdk->connect()) != srs_success) {
return srs_error_wrap(err, "edge pull %s failed, cto=%" PRId64 ", sto=%" PRId64, url.c_str(), cto, sto);
}
if ((err = sdk->play(_srs_config->get_chunk_size(req->vhost))) != srs_success) {
2018-01-01 11:39:57 +00:00
return srs_error_wrap(err, "edge pull %s stream failed", url.c_str());
}
2018-01-01 11:39:57 +00:00
return err;
}
2018-01-01 11:39:57 +00:00
srs_error_t SrsEdgeRtmpUpstream::recv_message(SrsCommonMessage** pmsg)
{
return sdk->recv_message(pmsg);
}
2018-01-01 11:39:57 +00:00
srs_error_t SrsEdgeRtmpUpstream::decode_message(SrsCommonMessage* msg, SrsPacket** ppacket)
{
return sdk->decode_message(msg, ppacket);
}
void SrsEdgeRtmpUpstream::close()
{
srs_freep(sdk);
}
void SrsEdgeRtmpUpstream::set_recv_timeout(int64_t tm)
{
sdk->set_recv_timeout(tm);
}
void SrsEdgeRtmpUpstream::kbps_sample(const char* label, int64_t age)
{
sdk->kbps_sample(label, age);
}
2014-04-26 10:08:21 +00:00
SrsEdgeIngester::SrsEdgeIngester()
{
2015-10-14 06:37:24 +00:00
source = NULL;
edge = NULL;
req = NULL;
2016-01-11 07:46:23 +00:00
upstream = new SrsEdgeRtmpUpstream(redirect);
lb = new SrsLbRoundRobin();
trd = new SrsDummyCoroutine();
2014-04-26 10:08:21 +00:00
}
SrsEdgeIngester::~SrsEdgeIngester()
2017-03-25 09:21:39 +00:00
{
stop();
srs_freep(upstream);
srs_freep(lb);
srs_freep(trd);
2014-04-26 10:08:21 +00:00
}
2017-06-11 01:40:07 +00:00
srs_error_t SrsEdgeIngester::initialize(SrsSource* s, SrsPlayEdge* e, SrsRequest* r)
2014-04-26 10:08:21 +00:00
{
2015-10-14 06:37:24 +00:00
source = s;
edge = e;
req = r;
2014-04-26 10:08:21 +00:00
2017-06-11 01:40:07 +00:00
return srs_success;
2014-04-26 10:08:21 +00:00
}
srs_error_t SrsEdgeIngester::start()
{
srs_error_t err = srs_success;
2017-03-25 09:21:39 +00:00
2017-09-23 14:12:33 +00:00
if ((err = source->on_publish()) != srs_success) {
return srs_error_wrap(err, "notify source");
}
2017-03-25 09:21:39 +00:00
srs_freep(trd);
trd = new SrsSTCoroutine("edge-igs", this);
if ((err = trd->start()) != srs_success) {
return srs_error_wrap(err, "coroutine");
}
return err;
}
void SrsEdgeIngester::stop()
{
trd->stop();
upstream->close();
// notice to unpublish.
2017-02-06 10:33:26 +00:00
if (source) {
source->on_unpublish();
}
}
2015-09-17 05:36:02 +00:00
string SrsEdgeIngester::get_curr_origin()
{
return lb->selected();
2015-09-17 05:36:02 +00:00
}
// when error, edge ingester sleep for a while and retry.
2019-04-07 08:25:52 +00:00
#define SRS_EDGE_INGESTER_CIMS (3 * SRS_UTIME_MILLISECONDS)
srs_error_t SrsEdgeIngester::cycle()
2014-04-26 10:08:21 +00:00
{
srs_error_t err = srs_success;
while (true) {
if ((err = do_cycle()) != srs_success) {
srs_warn("EdgeIngester: Ignore error, %s", srs_error_desc(err).c_str());
srs_freep(err);
}
if ((err = trd->pull()) != srs_success) {
return srs_error_wrap(err, "edge ingester");
}
2019-04-07 08:25:52 +00:00
srs_usleep(SRS_EDGE_INGESTER_CIMS);
}
return err;
}
srs_error_t SrsEdgeIngester::do_cycle()
{
srs_error_t err = srs_success;
while (true) {
if ((err = trd->pull()) != srs_success) {
return srs_error_wrap(err, "do cycle pull");
}
2016-01-11 07:46:23 +00:00
srs_freep(upstream);
upstream = new SrsEdgeRtmpUpstream(redirect);
// we only use the redict once.
// reset the redirect to empty, for maybe the origin changed.
redirect = "";
2017-09-23 14:12:33 +00:00
if ((err = source->on_source_id_changed(_srs_context->get_id())) != srs_success) {
return srs_error_wrap(err, "on source id changed");
2016-01-11 07:46:23 +00:00
}
2018-01-01 11:39:57 +00:00
if ((err = upstream->connect(req, lb)) != srs_success) {
return srs_error_wrap(err, "connect upstream");
2016-01-11 07:46:23 +00:00
}
2018-01-01 11:39:57 +00:00
if ((err = edge->on_ingest_play()) != srs_success) {
return srs_error_wrap(err, "notify edge play");
2016-01-11 07:46:23 +00:00
}
2017-09-23 14:12:33 +00:00
err = ingest();
2016-01-11 07:46:23 +00:00
// retry for rtmp 302 immediately.
2017-09-23 14:12:33 +00:00
if (srs_error_code(err) == ERROR_CONTROL_REDIRECT) {
srs_error_reset(err);
2016-01-11 07:46:23 +00:00
continue;
}
2017-09-23 14:12:33 +00:00
if (srs_is_client_gracefully_close(err)) {
srs_warn("origin disconnected, retry, error %s", srs_error_desc(err).c_str());
srs_error_reset(err);
2016-01-11 07:46:23 +00:00
}
break;
}
2018-01-01 11:39:57 +00:00
return err;
2014-04-26 10:08:21 +00:00
}
2017-09-23 14:12:33 +00:00
srs_error_t SrsEdgeIngester::ingest()
2014-04-26 10:08:21 +00:00
{
2017-09-23 14:12:33 +00:00
srs_error_t err = srs_success;
SrsPithyPrint* pprint = SrsPithyPrint::create_edge();
SrsAutoFree(SrsPithyPrint, pprint);
2015-10-14 06:37:24 +00:00
// set to larger timeout to read av data from origin.
upstream->set_recv_timeout(srsu2ms(SRS_EDGE_INGESTER_TMMS));
while (true) {
srs_error_t err = srs_success;
if ((err = trd->pull()) != srs_success) {
2017-09-23 14:12:33 +00:00
return srs_error_wrap(err, "thread quit");
}
pprint->elapse();
// pithy print
if (pprint->can_print()) {
upstream->kbps_sample(SRS_CONSTS_LOG_EDGE_PLAY, pprint->age());
}
2015-10-14 06:37:24 +00:00
// read from client.
SrsCommonMessage* msg = NULL;
2018-01-01 11:39:57 +00:00
if ((err = upstream->recv_message(&msg)) != srs_success) {
return srs_error_wrap(err, "recv message");
}
srs_assert(msg);
SrsAutoFree(SrsCommonMessage, msg);
2017-09-23 14:12:33 +00:00
if ((err = process_publish_message(msg)) != srs_success) {
return srs_error_wrap(err, "process message");
}
}
2017-09-23 14:12:33 +00:00
return err;
}
2017-09-23 14:12:33 +00:00
srs_error_t SrsEdgeIngester::process_publish_message(SrsCommonMessage* msg)
{
2017-09-23 14:12:33 +00:00
srs_error_t err = srs_success;
2017-03-25 09:21:39 +00:00
// process audio packet
if (msg->header.is_audio()) {
2017-09-23 14:12:33 +00:00
if ((err = source->on_audio(msg)) != srs_success) {
return srs_error_wrap(err, "source consume audio");
}
}
// process video packet
if (msg->header.is_video()) {
2017-09-23 14:12:33 +00:00
if ((err = source->on_video(msg)) != srs_success) {
return srs_error_wrap(err, "source consume video");
}
}
// process aggregate packet
if (msg->header.is_aggregate()) {
2017-09-23 14:12:33 +00:00
if ((err = source->on_aggregate(msg)) != srs_success) {
return srs_error_wrap(err, "source consume aggregate");
}
2017-09-23 14:12:33 +00:00
return err;
}
2017-03-25 09:21:39 +00:00
// process onMetaData
if (msg->header.is_amf0_data() || msg->header.is_amf3_data()) {
SrsPacket* pkt = NULL;
2018-01-01 11:39:57 +00:00
if ((err = upstream->decode_message(msg, &pkt)) != srs_success) {
return srs_error_wrap(err, "decode message");
}
SrsAutoFree(SrsPacket, pkt);
2017-03-25 09:21:39 +00:00
if (dynamic_cast<SrsOnMetaDataPacket*>(pkt)) {
SrsOnMetaDataPacket* metadata = dynamic_cast<SrsOnMetaDataPacket*>(pkt);
2017-09-23 14:12:33 +00:00
if ((err = source->on_meta_data(msg, metadata)) != srs_success) {
return srs_error_wrap(err, "source consume metadata");
}
2017-09-23 14:12:33 +00:00
return err;
}
2017-09-23 14:12:33 +00:00
return err;
}
2016-01-11 07:46:23 +00:00
// call messages, for example, reject, redirect.
if (msg->header.is_amf0_command() || msg->header.is_amf3_command()) {
SrsPacket* pkt = NULL;
2018-01-01 11:39:57 +00:00
if ((err = upstream->decode_message(msg, &pkt)) != srs_success) {
return srs_error_wrap(err, "decode message");
2016-01-11 07:46:23 +00:00
}
SrsAutoFree(SrsPacket, pkt);
// RTMP 302 redirect
if (dynamic_cast<SrsCallPacket*>(pkt)) {
SrsCallPacket* call = dynamic_cast<SrsCallPacket*>(pkt);
if (!call->arguments->is_object()) {
2017-09-23 14:12:33 +00:00
return err;
2016-01-11 07:46:23 +00:00
}
SrsAmf0Any* prop = NULL;
SrsAmf0Object* evt = call->arguments->to_object();
if ((prop = evt->ensure_property_string("level")) == NULL) {
2017-09-23 14:12:33 +00:00
return err;
2016-01-11 07:46:23 +00:00
} else if (prop->to_str() != StatusLevelError) {
2017-09-23 14:12:33 +00:00
return err;
2016-01-11 07:46:23 +00:00
}
if ((prop = evt->get_property("ex")) == NULL || !prop->is_object()) {
2017-09-23 14:12:33 +00:00
return err;
2016-01-11 07:46:23 +00:00
}
SrsAmf0Object* ex = prop->to_object();
if ((prop = ex->ensure_property_string("redirect")) == NULL) {
2017-09-23 14:12:33 +00:00
return err;
2016-01-11 07:46:23 +00:00
}
redirect = prop->to_str();
2017-09-23 14:12:33 +00:00
return srs_error_new(ERROR_CONTROL_REDIRECT, "RTMP 302 redirect to %s", redirect.c_str());
2016-01-11 07:46:23 +00:00
}
}
2017-09-23 14:12:33 +00:00
return err;
}
2014-04-27 01:29:37 +00:00
SrsEdgeForwarder::SrsEdgeForwarder()
{
2015-10-14 07:08:55 +00:00
edge = NULL;
req = NULL;
send_error_code = ERROR_SUCCESS;
sdk = NULL;
2015-09-24 10:33:07 +00:00
lb = new SrsLbRoundRobin();
trd = new SrsDummyCoroutine();
2014-04-28 09:20:35 +00:00
queue = new SrsMessageQueue();
2014-04-27 01:29:37 +00:00
}
SrsEdgeForwarder::~SrsEdgeForwarder()
{
stop();
2015-09-24 10:33:07 +00:00
srs_freep(lb);
srs_freep(trd);
srs_freep(queue);
2014-04-27 01:29:37 +00:00
}
2014-04-28 09:20:35 +00:00
void SrsEdgeForwarder::set_queue_size(double queue_size)
{
return queue->set_queue_size(queue_size);
}
2017-06-11 01:40:07 +00:00
srs_error_t SrsEdgeForwarder::initialize(SrsSource* s, SrsPublishEdge* e, SrsRequest* r)
2014-04-27 01:29:37 +00:00
{
2015-10-14 07:08:55 +00:00
source = s;
edge = e;
req = r;
2014-04-27 01:29:37 +00:00
2017-06-11 01:40:07 +00:00
return srs_success;
2014-04-27 01:29:37 +00:00
}
srs_error_t SrsEdgeForwarder::start()
2014-04-27 01:29:37 +00:00
{
srs_error_t err = srs_success;
2014-04-27 01:29:37 +00:00
2015-10-14 07:08:55 +00:00
// reset the error code.
2014-04-28 09:20:35 +00:00
send_error_code = ERROR_SUCCESS;
2015-10-14 07:08:55 +00:00
std::string url;
if (true) {
SrsConfDirective* conf = _srs_config->get_vhost_edge_origin(req->vhost);
srs_assert(conf);
// select the origin.
std::string server = lb->select(conf->args);
int port = SRS_CONSTS_RTMP_DEFAULT_PORT;
srs_parse_hostport(server, server, port);
// support vhost tranform for edge,
2015-11-11 02:45:45 +00:00
// @see https://github.com/ossrs/srs/issues/372
2015-10-14 07:08:55 +00:00
std::string vhost = _srs_config->get_vhost_edge_transform_vhost(req->vhost);
vhost = srs_string_replace(vhost, "[vhost]", req->vhost);
url = srs_generate_rtmp_url(server, port, req->host, vhost, req->app, req->stream, req->param);
}
2015-10-14 07:08:55 +00:00
// open socket.
srs_freep(sdk);
int64_t cto = srsu2ms(SRS_EDGE_FORWARDER_TMMS);
int64_t sto = SRS_CONSTS_RTMP_TMMS;
sdk = new SrsSimpleRtmpClient(url, cto, sto);
2018-01-01 11:39:57 +00:00
if ((err = sdk->connect()) != srs_success) {
return srs_error_wrap(err, "sdk connect %s failed, cto=%" PRId64 ", sto=%" PRId64, url.c_str(), cto, sto);
2014-04-27 01:29:37 +00:00
}
if ((err = sdk->publish(_srs_config->get_chunk_size(req->vhost))) != srs_success) {
2018-01-01 11:39:57 +00:00
return srs_error_wrap(err, "sdk publish");
2014-04-27 01:29:37 +00:00
}
srs_freep(trd);
trd = new SrsSTCoroutine("edge-fwr", this);
if ((err = trd->start()) != srs_success) {
return srs_error_wrap(err, "coroutine");
}
srs_trace("edge-fwr publish url %s", url.c_str());
return err;
2014-04-27 01:29:37 +00:00
}
void SrsEdgeForwarder::stop()
{
trd->stop();
2015-09-14 07:19:49 +00:00
queue->clear();
srs_freep(sdk);
}
// when error, edge ingester sleep for a while and retry.
2019-04-07 08:25:52 +00:00
#define SRS_EDGE_FORWARDER_CIMS (3 * SRS_UTIME_MILLISECONDS)
srs_error_t SrsEdgeForwarder::cycle()
{
srs_error_t err = srs_success;
while (true) {
if ((err = do_cycle()) != srs_success) {
return srs_error_wrap(err, "do cycle");
}
if ((err = trd->pull()) != srs_success) {
return srs_error_wrap(err, "thread pull");
}
2019-04-07 08:25:52 +00:00
srs_usleep(SRS_EDGE_FORWARDER_CIMS);
}
return err;
}
#define SYS_MAX_EDGE_SEND_MSGS 128
srs_error_t SrsEdgeForwarder::do_cycle()
{
srs_error_t err = srs_success;
sdk->set_recv_timeout(SRS_CONSTS_RTMP_PULSE_TMMS);
SrsPithyPrint* pprint = SrsPithyPrint::create_edge();
SrsAutoFree(SrsPithyPrint, pprint);
SrsMessageArray msgs(SYS_MAX_EDGE_SEND_MSGS);
2017-03-25 09:21:39 +00:00
while (true) {
if ((err = trd->pull()) != srs_success) {
return srs_error_wrap(err, "edge forward pull");
}
2014-04-28 09:20:35 +00:00
if (send_error_code != ERROR_SUCCESS) {
2019-04-07 08:25:52 +00:00
srs_usleep(SRS_EDGE_FORWARDER_TMMS);
2014-04-28 09:20:35 +00:00
continue;
}
2017-03-25 09:21:39 +00:00
2014-04-28 09:20:35 +00:00
// read from client.
if (true) {
SrsCommonMessage* msg = NULL;
2018-01-01 11:39:57 +00:00
err = sdk->recv_message(&msg);
2014-04-28 09:20:35 +00:00
srs_verbose("edge loop recv message. ret=%d", ret);
2018-01-01 11:39:57 +00:00
if (err != srs_success && srs_error_code(err) != ERROR_SOCKET_TIMEOUT) {
srs_error("edge push get server control message failed. err=%s", srs_error_desc(err).c_str());
send_error_code = srs_error_code(err);
srs_error_reset(err);
2014-04-28 09:20:35 +00:00
continue;
}
2018-01-01 11:39:57 +00:00
srs_error_reset(err);
2014-04-28 09:20:35 +00:00
srs_freep(msg);
}
// forward all messages.
// each msg in msgs.msgs must be free, for the SrsMessageArray never free them.
2014-04-28 09:20:35 +00:00
int count = 0;
2017-09-23 14:12:33 +00:00
if ((err = queue->dump_packets(msgs.max, msgs.msgs, count)) != srs_success) {
return srs_error_wrap(err, "queue dumps packets");
2014-04-28 09:20:35 +00:00
}
pprint->elapse();
// pithy print
if (pprint->can_print()) {
2015-10-14 07:08:55 +00:00
sdk->kbps_sample(SRS_CONSTS_LOG_EDGE_PUBLISH, pprint->age(), count);
}
2014-04-28 09:20:35 +00:00
// ignore when no messages.
if (count <= 0) {
2015-10-14 07:08:55 +00:00
srs_verbose("edge no packets to push.");
continue;
}
2017-03-25 09:21:39 +00:00
// sendout messages, all messages are freed by send_and_free_messages().
2018-01-01 11:39:57 +00:00
if ((err = sdk->send_and_free_messages(msgs.msgs, count)) != srs_success) {
return srs_error_wrap(err, "send messages");
2014-04-28 09:20:35 +00:00
}
}
return err;
}
2017-09-23 14:12:33 +00:00
srs_error_t SrsEdgeForwarder::proxy(SrsCommonMessage* msg)
2014-04-27 01:29:37 +00:00
{
2017-09-23 14:12:33 +00:00
srs_error_t err = srs_success;
2014-04-27 01:29:37 +00:00
2018-01-01 11:39:57 +00:00
if (send_error_code != ERROR_SUCCESS) {
return srs_error_new(send_error_code, "edge forwarder");
2014-04-28 09:20:35 +00:00
}
2014-04-27 06:57:28 +00:00
// the msg is auto free by source,
// so we just ignore, or copy then send it.
if (msg->size <= 0
|| msg->header.is_set_chunk_size()
|| msg->header.is_window_ackledgement_size()
2017-09-23 14:12:33 +00:00
|| msg->header.is_ackledgement()) {
return err;
}
SrsSharedPtrMessage copy;
2018-01-01 11:39:57 +00:00
if ((err = copy.create(msg)) != srs_success) {
return srs_error_wrap(err, "create message");
}
2015-10-14 07:08:55 +00:00
copy.stream_id = sdk->sid();
2017-09-23 14:12:33 +00:00
if ((err = queue->enqueue(copy.copy())) != srs_success) {
return srs_error_wrap(err, "enqueue message");
2014-04-27 01:29:37 +00:00
}
2017-09-23 14:12:33 +00:00
return err;
2014-04-27 01:29:37 +00:00
}
SrsPlayEdge::SrsPlayEdge()
{
state = SrsEdgeStateInit;
2014-04-26 10:08:21 +00:00
ingester = new SrsEdgeIngester();
}
2014-04-27 01:29:37 +00:00
SrsPlayEdge::~SrsPlayEdge()
{
2014-04-26 10:08:21 +00:00
srs_freep(ingester);
}
2017-06-11 01:40:07 +00:00
srs_error_t SrsPlayEdge::initialize(SrsSource* source, SrsRequest* req)
2014-04-26 09:16:18 +00:00
{
2017-06-11 01:40:07 +00:00
srs_error_t err = srs_success;
2014-04-26 09:16:18 +00:00
2017-06-11 01:40:07 +00:00
if ((err = ingester->initialize(source, this, req)) != srs_success) {
return srs_error_wrap(err, "ingester(pull)");
2014-04-26 10:08:21 +00:00
}
2014-04-26 09:16:18 +00:00
2017-06-11 01:40:07 +00:00
return err;
2014-04-26 09:16:18 +00:00
}
2018-01-01 11:39:57 +00:00
srs_error_t SrsPlayEdge::on_client_play()
{
srs_error_t err = srs_success;
2014-04-26 10:08:21 +00:00
// start ingest when init state.
if (state == SrsEdgeStateInit) {
state = SrsEdgeStatePlay;
err = ingester->start();
2014-04-26 10:08:21 +00:00
}
2017-03-25 09:21:39 +00:00
2018-01-01 11:39:57 +00:00
return err;
}
2014-04-27 01:29:37 +00:00
void SrsPlayEdge::on_all_client_stop()
{
// when all client disconnected,
// and edge is ingesting origin stream, abort it.
if (state == SrsEdgeStatePlay || state == SrsEdgeStateIngestConnected) {
ingester->stop();
2017-03-25 09:21:39 +00:00
SrsEdgeState pstate = state;
state = SrsEdgeStateInit;
srs_trace("edge change from %d to state %d (init).", pstate, state);
return;
}
}
2015-09-17 05:36:02 +00:00
string SrsPlayEdge::get_curr_origin()
{
return ingester->get_curr_origin();
}
2018-01-01 11:39:57 +00:00
srs_error_t SrsPlayEdge::on_ingest_play()
{
2018-01-01 11:39:57 +00:00
srs_error_t err = srs_success;
// when already connected(for instance, reconnect for error), ignore.
if (state == SrsEdgeStateIngestConnected) {
2018-01-01 11:39:57 +00:00
return err;
}
srs_assert(state == SrsEdgeStatePlay);
SrsEdgeState pstate = state;
state = SrsEdgeStateIngestConnected;
2014-07-21 07:30:44 +00:00
srs_trace("edge change from %d to state %d (pull).", pstate, state);
2018-01-01 11:39:57 +00:00
return err;
}
2014-04-27 01:29:37 +00:00
SrsPublishEdge::SrsPublishEdge()
{
state = SrsEdgeStateInit;
forwarder = new SrsEdgeForwarder();
}
SrsPublishEdge::~SrsPublishEdge()
{
srs_freep(forwarder);
}
2014-04-28 09:20:35 +00:00
void SrsPublishEdge::set_queue_size(double queue_size)
{
return forwarder->set_queue_size(queue_size);
}
2017-06-11 01:40:07 +00:00
srs_error_t SrsPublishEdge::initialize(SrsSource* source, SrsRequest* req)
2014-04-27 01:29:37 +00:00
{
2017-06-11 01:40:07 +00:00
srs_error_t err = srs_success;
2017-03-25 09:21:39 +00:00
2017-06-11 01:40:07 +00:00
if ((err = forwarder->initialize(source, this, req)) != srs_success) {
return srs_error_wrap(err, "forwarder(push)");
2014-04-27 01:29:37 +00:00
}
2017-06-11 01:40:07 +00:00
return err;
2014-04-27 01:29:37 +00:00
}
bool SrsPublishEdge::can_publish()
{
return state != SrsEdgeStatePublish;
}
2017-09-23 14:12:33 +00:00
srs_error_t SrsPublishEdge::on_client_publish()
2014-04-27 01:29:37 +00:00
{
srs_error_t err = srs_success;
2014-04-27 01:29:37 +00:00
// error when not init state.
if (state != SrsEdgeStateInit) {
2017-09-23 14:12:33 +00:00
return srs_error_new(ERROR_RTMP_EDGE_PUBLISH_STATE, "invalid state");
2014-04-27 01:29:37 +00:00
}
2015-11-11 02:37:50 +00:00
// @see https://github.com/ossrs/srs/issues/180
// to avoid multiple publish the same stream on the same edge,
// directly enter the publish stage.
if (true) {
SrsEdgeState pstate = state;
state = SrsEdgeStatePublish;
srs_trace("edge change from %d to state %d (push).", pstate, state);
2014-04-28 09:20:35 +00:00
}
// start to forward stream to origin.
err = forwarder->start();
2015-11-11 02:37:50 +00:00
// @see https://github.com/ossrs/srs/issues/180
// when failed, revert to init
2017-09-23 14:12:33 +00:00
if (err != srs_success) {
SrsEdgeState pstate = state;
state = SrsEdgeStateInit;
2017-09-23 14:12:33 +00:00
srs_trace("edge revert from %d to state %d (push), error %s", pstate, state, srs_error_desc(err).c_str());
}
2017-09-23 14:12:33 +00:00
return err;
2014-04-27 01:29:37 +00:00
}
2017-09-23 14:12:33 +00:00
srs_error_t SrsPublishEdge::on_proxy_publish(SrsCommonMessage* msg)
2014-04-27 01:29:37 +00:00
{
2014-04-27 06:57:28 +00:00
return forwarder->proxy(msg);
}
void SrsPublishEdge::on_proxy_unpublish()
{
if (state == SrsEdgeStatePublish) {
forwarder->stop();
}
SrsEdgeState pstate = state;
state = SrsEdgeStateInit;
srs_trace("edge change from %d to state %d (init).", pstate, state);
2014-04-27 01:29:37 +00:00
}
2014-08-02 14:18:39 +00:00