2013-12-14 06:06:32 +00:00
|
|
|
/*
|
|
|
|
The MIT License (MIT)
|
|
|
|
|
2016-12-16 03:57:25 +00:00
|
|
|
Copyright (c) 2013-2017 SRS(ossrs)
|
2013-12-14 06:06:32 +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-03-02 13:49:09 +00:00
|
|
|
#include <srs_app_forward.hpp>
|
2013-12-14 06:06:32 +00:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
2014-08-19 03:54:33 +00:00
|
|
|
using namespace std;
|
|
|
|
|
2014-03-02 13:49:09 +00:00
|
|
|
#include <srs_app_source.hpp>
|
2015-06-14 00:43:38 +00:00
|
|
|
#include <srs_app_st.hpp>
|
2014-03-01 02:30:16 +00:00
|
|
|
#include <srs_kernel_error.hpp>
|
2014-03-01 02:42:55 +00:00
|
|
|
#include <srs_kernel_log.hpp>
|
2014-03-02 13:49:09 +00:00
|
|
|
#include <srs_app_config.hpp>
|
|
|
|
#include <srs_app_pithy_print.hpp>
|
2015-06-13 08:04:59 +00:00
|
|
|
#include <srs_rtmp_stack.hpp>
|
2015-09-22 01:11:07 +00:00
|
|
|
#include <srs_protocol_utility.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>
|
2014-06-29 06:39:56 +00:00
|
|
|
#include <srs_app_utility.hpp>
|
2015-09-22 01:05:21 +00:00
|
|
|
#include <srs_protocol_amf0.hpp>
|
2014-08-24 14:34:38 +00:00
|
|
|
#include <srs_kernel_codec.hpp>
|
2015-02-19 10:56:21 +00:00
|
|
|
#include <srs_core_autofree.hpp>
|
2015-09-24 10:33:07 +00:00
|
|
|
#include <srs_kernel_utility.hpp>
|
2015-10-14 07:34:18 +00:00
|
|
|
#include <srs_app_rtmp_conn.hpp>
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-04-07 01:07:12 +00:00
|
|
|
// when error, forwarder sleep for a while and retry.
|
|
|
|
#define SRS_FORWARDER_SLEEP_US (int64_t)(3*1000*1000LL)
|
|
|
|
|
2015-10-14 07:34:18 +00:00
|
|
|
SrsForwarder::SrsForwarder(SrsSource* s)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2015-10-14 07:34:18 +00:00
|
|
|
source = s;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2015-10-14 07:34:18 +00:00
|
|
|
req = NULL;
|
|
|
|
sh_video = sh_audio = NULL;
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2017-01-17 02:44:13 +00:00
|
|
|
sdk = NULL;
|
2015-05-23 01:49:15 +00:00
|
|
|
pthread = new SrsReusableThread2("forward", this, SRS_FORWARDER_SLEEP_US);
|
2014-03-18 03:32:58 +00:00
|
|
|
queue = new SrsMessageQueue();
|
|
|
|
jitter = new SrsRtmpJitter();
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsForwarder::~SrsForwarder()
|
|
|
|
{
|
2015-10-14 07:34:18 +00:00
|
|
|
srs_freep(sdk);
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(pthread);
|
|
|
|
srs_freep(queue);
|
|
|
|
srs_freep(jitter);
|
2014-08-24 14:34:38 +00:00
|
|
|
|
|
|
|
srs_freep(sh_video);
|
|
|
|
srs_freep(sh_audio);
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
2015-10-14 07:34:18 +00:00
|
|
|
int SrsForwarder::initialize(SrsRequest* r, string ep)
|
2014-08-19 03:54:33 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// it's ok to use the request object,
|
|
|
|
// SrsSource already copy it and never delete it.
|
2015-10-14 07:34:18 +00:00
|
|
|
req = r;
|
2014-08-19 03:54:33 +00:00
|
|
|
|
|
|
|
// the ep(endpoint) to forward to
|
2015-10-14 07:34:18 +00:00
|
|
|
ep_forward = ep;
|
2014-08-19 03:54:33 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-12-15 10:25:55 +00:00
|
|
|
void SrsForwarder::set_queue_size(double queue_size)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
queue->set_queue_size(queue_size);
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-08-19 03:54:33 +00:00
|
|
|
int SrsForwarder::on_publish()
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-08-19 03:54:33 +00:00
|
|
|
// discovery the server port and tcUrl from req and ep_forward.
|
2015-10-14 07:34:18 +00:00
|
|
|
std::string server;
|
|
|
|
std::string tcUrl;
|
|
|
|
int port = SRS_CONSTS_RTMP_DEFAULT_PORT;
|
|
|
|
if (true) {
|
|
|
|
// parse host:port from hostport.
|
|
|
|
srs_parse_hostport(ep_forward, server, port);
|
|
|
|
|
|
|
|
// generate tcUrl
|
|
|
|
tcUrl = srs_generate_tc_url(server, req->vhost, req->app, port, req->param);
|
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
// dead loop check
|
2014-03-26 04:34:35 +00:00
|
|
|
std::string source_ep = "rtmp://";
|
|
|
|
source_ep += req->host;
|
2014-03-18 03:32:58 +00:00
|
|
|
source_ep += ":";
|
|
|
|
source_ep += req->port;
|
2014-03-26 04:34:35 +00:00
|
|
|
source_ep += "?vhost=";
|
|
|
|
source_ep += req->vhost;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-03-26 04:34:35 +00:00
|
|
|
std::string dest_ep = "rtmp://";
|
2015-10-14 07:34:18 +00:00
|
|
|
if (ep_forward == SRS_CONSTS_LOCALHOST) {
|
2014-03-26 04:34:35 +00:00
|
|
|
dest_ep += req->host;
|
|
|
|
} else {
|
2014-12-29 01:05:56 +00:00
|
|
|
dest_ep += server;
|
2014-03-26 04:34:35 +00:00
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
dest_ep += ":";
|
2014-08-19 03:54:33 +00:00
|
|
|
dest_ep += port;
|
2014-03-26 04:34:35 +00:00
|
|
|
dest_ep += "?vhost=";
|
2014-08-19 03:54:33 +00:00
|
|
|
dest_ep += req->vhost;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
if (source_ep == dest_ep) {
|
|
|
|
ret = ERROR_SYSTEM_FORWARD_LOOP;
|
2014-03-26 04:34:35 +00:00
|
|
|
srs_warn("forward loop detected. src=%s, dest=%s, ret=%d",
|
2014-03-18 03:32:58 +00:00
|
|
|
source_ep.c_str(), dest_ep.c_str(), ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2014-05-17 06:53:04 +00:00
|
|
|
srs_trace("start forward %s to %s, tcUrl=%s, stream=%s",
|
2015-10-14 07:34:18 +00:00
|
|
|
source_ep.c_str(), dest_ep.c_str(), tcUrl.c_str(),
|
2014-08-19 03:54:33 +00:00
|
|
|
req->stream.c_str());
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
if ((ret = pthread->start()) != ERROR_SUCCESS) {
|
2013-12-14 06:06:32 +00:00
|
|
|
srs_error("start srs thread failed. ret=%d", ret);
|
|
|
|
return ret;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2014-04-16 08:58:54 +00:00
|
|
|
srs_trace("forward thread cid=%d, current_cid=%d", pthread->cid(), _srs_context->get_id());
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsForwarder::on_unpublish()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
pthread->stop();
|
2015-10-14 07:34:18 +00:00
|
|
|
sdk->close();
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2015-03-21 03:55:28 +00:00
|
|
|
int SrsForwarder::on_meta_data(SrsSharedPtrMessage* shared_metadata)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
2014-12-05 15:49:53 +00:00
|
|
|
|
2015-03-21 03:55:28 +00:00
|
|
|
SrsSharedPtrMessage* metadata = shared_metadata->copy();
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2015-06-10 07:38:13 +00:00
|
|
|
// TODO: FIXME: config the jitter of Forwarder.
|
2015-07-14 02:03:15 +00:00
|
|
|
if ((ret = jitter->correct(metadata, SrsRtmpJitterAlgorithmOFF)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(metadata);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = queue->enqueue(metadata)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2015-03-21 03:55:28 +00:00
|
|
|
int SrsForwarder::on_audio(SrsSharedPtrMessage* shared_audio)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2015-03-21 03:55:28 +00:00
|
|
|
SrsSharedPtrMessage* msg = shared_audio->copy();
|
2015-06-10 07:38:13 +00:00
|
|
|
|
|
|
|
// TODO: FIXME: config the jitter of Forwarder.
|
2015-07-14 02:03:15 +00:00
|
|
|
if ((ret = jitter->correct(msg, SrsRtmpJitterAlgorithmOFF)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(msg);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-08-24 14:34:38 +00:00
|
|
|
if (SrsFlvCodec::audio_is_sequence_header(msg->payload, msg->size)) {
|
|
|
|
srs_freep(sh_audio);
|
|
|
|
sh_audio = msg->copy();
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
if ((ret = queue->enqueue(msg)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2015-03-21 03:55:28 +00:00
|
|
|
int SrsForwarder::on_video(SrsSharedPtrMessage* shared_video)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
2014-12-05 15:49:53 +00:00
|
|
|
|
2015-03-21 03:55:28 +00:00
|
|
|
SrsSharedPtrMessage* msg = shared_video->copy();
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2015-06-10 07:38:13 +00:00
|
|
|
// TODO: FIXME: config the jitter of Forwarder.
|
2015-07-14 02:03:15 +00:00
|
|
|
if ((ret = jitter->correct(msg, SrsRtmpJitterAlgorithmOFF)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(msg);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-08-24 14:34:38 +00:00
|
|
|
if (SrsFlvCodec::video_is_sequence_header(msg->payload, msg->size)) {
|
|
|
|
srs_freep(sh_video);
|
|
|
|
sh_video = msg->copy();
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
if ((ret = queue->enqueue(msg)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsForwarder::cycle()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2015-10-14 07:34:18 +00:00
|
|
|
std::string url;
|
|
|
|
if (true) {
|
|
|
|
std::string server;
|
|
|
|
int port = SRS_CONSTS_RTMP_DEFAULT_PORT;
|
|
|
|
|
|
|
|
// parse host:port from hostport.
|
|
|
|
srs_parse_hostport(ep_forward, server, port);
|
|
|
|
|
|
|
|
// generate url
|
|
|
|
url = srs_generate_rtmp_url(server, port, req->vhost, req->app, req->stream);
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2017-01-17 02:44:13 +00:00
|
|
|
srs_freep(sdk);
|
2015-10-14 07:34:18 +00:00
|
|
|
int64_t cto = SRS_FORWARDER_SLEEP_US;
|
|
|
|
int64_t sto = SRS_CONSTS_RTMP_TIMEOUT_US;
|
2017-01-17 02:44:13 +00:00
|
|
|
sdk = new SrsSimpleRtmpClient(url, cto, sto);
|
|
|
|
|
|
|
|
if ((ret = sdk->connect()) != ERROR_SUCCESS) {
|
2015-10-14 07:34:18 +00:00
|
|
|
srs_warn("forward failed, url=%s, cto=%"PRId64", sto=%"PRId64". ret=%d", url.c_str(), cto, sto, ret);
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-10-14 07:34:18 +00:00
|
|
|
if ((ret = sdk->publish()) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = source->on_forwarder_start(this)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("callback the source to feed the sequence header failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = forward()) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-06-22 12:01:25 +00:00
|
|
|
#define SYS_MAX_FORWARD_SEND_MSGS 128
|
2013-12-14 06:06:32 +00:00
|
|
|
int SrsForwarder::forward()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2015-10-14 07:34:18 +00:00
|
|
|
sdk->set_recv_timeout(SRS_CONSTS_RTMP_PULSE_TIMEOUT_US);
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2015-02-19 10:56:21 +00:00
|
|
|
SrsPithyPrint* pprint = SrsPithyPrint::create_forwarder();
|
|
|
|
SrsAutoFree(SrsPithyPrint, pprint);
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-11-13 08:56:41 +00:00
|
|
|
SrsMessageArray msgs(SYS_MAX_FORWARD_SEND_MSGS);
|
2014-06-22 12:01:25 +00:00
|
|
|
|
2014-08-24 14:34:38 +00:00
|
|
|
// update sequence header
|
|
|
|
// TODO: FIXME: maybe need to zero the sequence header timestamp.
|
|
|
|
if (sh_video) {
|
2015-10-14 07:34:18 +00:00
|
|
|
if ((ret = sdk->send_and_free_message(sh_video->copy())) != ERROR_SUCCESS) {
|
2014-08-24 14:34:38 +00:00
|
|
|
srs_error("forwarder send sh_video to server failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sh_audio) {
|
2015-10-14 07:34:18 +00:00
|
|
|
if ((ret = sdk->send_and_free_message(sh_audio->copy())) != ERROR_SUCCESS) {
|
2014-08-24 14:34:38 +00:00
|
|
|
srs_error("forwarder send sh_audio to server failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-23 01:20:16 +00:00
|
|
|
while (!pthread->interrupted()) {
|
2015-02-19 10:56:21 +00:00
|
|
|
pprint->elapse();
|
2014-04-26 13:41:18 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// read from client.
|
|
|
|
if (true) {
|
2014-12-05 15:03:52 +00:00
|
|
|
SrsCommonMessage* msg = NULL;
|
2015-10-14 07:34:18 +00:00
|
|
|
ret = sdk->recv_message(&msg);
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
srs_verbose("play loop recv message. ret=%d", ret);
|
|
|
|
if (ret != ERROR_SUCCESS && ret != ERROR_SOCKET_TIMEOUT) {
|
|
|
|
srs_error("recv server control message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2014-04-28 09:20:35 +00:00
|
|
|
|
|
|
|
srs_freep(msg);
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// forward all messages.
|
2014-11-19 02:44:50 +00:00
|
|
|
// each msg in msgs.msgs must be free, for the SrsMessageArray never free them.
|
2014-03-18 03:32:58 +00:00
|
|
|
int count = 0;
|
2014-11-14 03:24:49 +00:00
|
|
|
if ((ret = queue->dump_packets(msgs.max, msgs.msgs, count)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("get message to forward failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-26 13:41:18 +00:00
|
|
|
// pithy print
|
2015-02-19 10:56:21 +00:00
|
|
|
if (pprint->can_print()) {
|
2015-10-14 07:34:18 +00:00
|
|
|
sdk->kbps_sample(SRS_CONSTS_LOG_FOWARDER, pprint->age(), count);
|
2014-04-26 13:41:18 +00:00
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// ignore when no messages.
|
|
|
|
if (count <= 0) {
|
|
|
|
srs_verbose("no packets to forward.");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-11-19 02:44:50 +00:00
|
|
|
// sendout messages, all messages are freed by send_and_free_messages().
|
2015-10-14 07:34:18 +00:00
|
|
|
if ((ret = sdk->send_and_free_messages(msgs.msgs, count)) != ERROR_SUCCESS) {
|
2014-11-14 03:24:49 +00:00
|
|
|
srs_error("forwarder messages to server failed. ret=%d", ret);
|
|
|
|
return ret;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-08-02 14:18:39 +00:00
|
|
|
|