2013-12-14 06:06:32 +00:00
|
|
|
/*
|
|
|
|
The MIT License (MIT)
|
|
|
|
|
2014-01-01 02:37:12 +00:00
|
|
|
Copyright (c) 2013-2014 winlin
|
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_source.hpp>
|
2013-12-14 06:06:32 +00:00
|
|
|
|
|
|
|
#include <algorithm>
|
2013-12-15 04:04:28 +00:00
|
|
|
using namespace std;
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-03-01 02:42:55 +00:00
|
|
|
#include <srs_kernel_log.hpp>
|
2014-03-01 05:39:27 +00:00
|
|
|
#include <srs_protocol_rtmp_stack.hpp>
|
2013-12-14 06:06:32 +00:00
|
|
|
#include <srs_core_autofree.hpp>
|
2014-03-01 03:24:40 +00:00
|
|
|
#include <srs_protocol_amf0.hpp>
|
2014-03-02 13:49:09 +00:00
|
|
|
#include <srs_app_codec.hpp>
|
|
|
|
#include <srs_app_hls.hpp>
|
|
|
|
#include <srs_app_forward.hpp>
|
|
|
|
#include <srs_app_config.hpp>
|
|
|
|
#include <srs_app_encoder.hpp>
|
2014-03-01 06:03:02 +00:00
|
|
|
#include <srs_protocol_rtmp.hpp>
|
2014-04-16 01:28:02 +00:00
|
|
|
#include <srs_app_dvr.hpp>
|
2014-04-17 08:06:49 +00:00
|
|
|
#include <srs_kernel_stream.hpp>
|
2014-04-26 06:47:38 +00:00
|
|
|
#include <srs_app_edge.hpp>
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
#define CONST_MAX_JITTER_MS 500
|
|
|
|
#define DEFAULT_FRAME_TIME_MS 40
|
2013-12-14 06:06:32 +00:00
|
|
|
|
|
|
|
SrsRtmpJitter::SrsRtmpJitter()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
last_pkt_correct_time = last_pkt_time = 0;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsRtmpJitter::~SrsRtmpJitter()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// set to 0 for metadata.
|
|
|
|
if (!msg->header.is_video() && !msg->header.is_audio()) {
|
|
|
|
msg->header.timestamp = 0;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sample_rate = tba;
|
|
|
|
int frame_rate = tbv;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* we use a very simple time jitter detect/correct algorithm:
|
|
|
|
* 1. delta: ensure the delta is positive and valid,
|
|
|
|
* we set the delta to DEFAULT_FRAME_TIME_MS,
|
|
|
|
* if the delta of time is nagative or greater than CONST_MAX_JITTER_MS.
|
|
|
|
* 2. last_pkt_time: specifies the original packet time,
|
|
|
|
* is used to detect next jitter.
|
|
|
|
* 3. last_pkt_correct_time: simply add the positive delta,
|
|
|
|
* and enforce the time monotonically.
|
|
|
|
*/
|
|
|
|
int64_t time = msg->header.timestamp;
|
|
|
|
int64_t delta = time - last_pkt_time;
|
|
|
|
|
|
|
|
// if jitter detected, reset the delta.
|
|
|
|
if (delta < 0 || delta > CONST_MAX_JITTER_MS) {
|
|
|
|
// calc the right diff by audio sample rate
|
|
|
|
if (msg->header.is_audio() && sample_rate > 0) {
|
|
|
|
delta = (int64_t)(delta * 1000.0 / sample_rate);
|
|
|
|
} else if (msg->header.is_video() && frame_rate > 0) {
|
|
|
|
delta = (int64_t)(delta * 1.0 / frame_rate);
|
|
|
|
} else {
|
|
|
|
delta = DEFAULT_FRAME_TIME_MS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// sometimes, the time is absolute time, so correct it again.
|
|
|
|
if (delta < 0 || delta > CONST_MAX_JITTER_MS) {
|
|
|
|
delta = DEFAULT_FRAME_TIME_MS;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_info("jitter detected, last_pts=%"PRId64", pts=%"PRId64", diff=%"PRId64", last_time=%"PRId64", time=%"PRId64", diff=%"PRId64"",
|
|
|
|
last_pkt_time, time, time - last_pkt_time, last_pkt_correct_time, last_pkt_correct_time + delta, delta);
|
|
|
|
} else {
|
|
|
|
srs_verbose("timestamp no jitter. time=%"PRId64", last_pkt=%"PRId64", correct_to=%"PRId64"",
|
|
|
|
time, last_pkt_time, last_pkt_correct_time + delta);
|
|
|
|
}
|
|
|
|
|
|
|
|
last_pkt_correct_time = srs_max(0, last_pkt_correct_time + delta);
|
|
|
|
|
|
|
|
msg->header.timestamp = last_pkt_correct_time;
|
|
|
|
last_pkt_time = time;
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsRtmpJitter::get_time()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return (int)last_pkt_correct_time;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 10:25:55 +00:00
|
|
|
SrsMessageQueue::SrsMessageQueue()
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
queue_size_ms = 0;
|
|
|
|
av_start_time = av_end_time = -1;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 10:25:55 +00:00
|
|
|
SrsMessageQueue::~SrsMessageQueue()
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
clear();
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 10:25:55 +00:00
|
|
|
void SrsMessageQueue::set_queue_size(double queue_size)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
queue_size_ms = (int)(queue_size * 1000);
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
int SrsMessageQueue::enqueue(SrsSharedPtrMessage* msg)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
if (msg->header.is_video() || msg->header.is_audio()) {
|
|
|
|
if (av_start_time == -1) {
|
|
|
|
av_start_time = msg->header.timestamp;
|
|
|
|
}
|
|
|
|
|
|
|
|
av_end_time = msg->header.timestamp;
|
|
|
|
}
|
|
|
|
|
|
|
|
msgs.push_back(msg);
|
|
|
|
|
|
|
|
while (av_end_time - av_start_time > queue_size_ms) {
|
|
|
|
shrink();
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
int SrsMessageQueue::get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& count)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
if (msgs.empty()) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (max_count == 0) {
|
|
|
|
count = (int)msgs.size();
|
|
|
|
} else {
|
|
|
|
count = srs_min(max_count, (int)msgs.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count <= 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
pmsgs = new SrsSharedPtrMessage*[count];
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
pmsgs[i] = msgs[i];
|
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
SrsSharedPtrMessage* last = msgs[count - 1];
|
2014-03-18 03:32:58 +00:00
|
|
|
av_start_time = last->header.timestamp;
|
|
|
|
|
|
|
|
if (count == (int)msgs.size()) {
|
|
|
|
msgs.clear();
|
|
|
|
} else {
|
|
|
|
msgs.erase(msgs.begin(), msgs.begin() + count);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 10:25:55 +00:00
|
|
|
void SrsMessageQueue::shrink()
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int iframe_index = -1;
|
|
|
|
|
|
|
|
// issue the first iframe.
|
|
|
|
// skip the first frame, whatever the type of it,
|
|
|
|
// for when we shrinked, the first is the iframe,
|
|
|
|
// we will directly remove the gop next time.
|
|
|
|
for (int i = 1; i < (int)msgs.size(); i++) {
|
2014-04-29 06:44:07 +00:00
|
|
|
SrsSharedPtrMessage* msg = msgs[i];
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
if (msg->header.is_video()) {
|
|
|
|
if (SrsCodec::video_is_keyframe(msg->payload, msg->size)) {
|
|
|
|
// the max frame index to remove.
|
|
|
|
iframe_index = i;
|
|
|
|
|
|
|
|
// set the start time, we will remove until this frame.
|
|
|
|
av_start_time = msg->header.timestamp;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// no iframe, clear the queue.
|
|
|
|
if (iframe_index < 0) {
|
|
|
|
clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_trace("shrink the cache queue, size=%d, removed=%d, max=%.2f",
|
|
|
|
(int)msgs.size(), iframe_index, queue_size_ms / 1000.0);
|
|
|
|
|
|
|
|
// remove the first gop from the front
|
|
|
|
for (int i = 0; i < iframe_index; i++) {
|
2014-04-29 06:44:07 +00:00
|
|
|
SrsSharedPtrMessage* msg = msgs[i];
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(msg);
|
|
|
|
}
|
|
|
|
msgs.erase(msgs.begin(), msgs.begin() + iframe_index);
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 10:25:55 +00:00
|
|
|
void SrsMessageQueue::clear()
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-04-29 06:44:07 +00:00
|
|
|
std::vector<SrsSharedPtrMessage*>::iterator it;
|
2013-12-15 10:25:55 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
for (it = msgs.begin(); it != msgs.end(); ++it) {
|
2014-04-29 06:44:07 +00:00
|
|
|
SrsSharedPtrMessage* msg = *it;
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(msg);
|
|
|
|
}
|
2013-12-15 10:25:55 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
msgs.clear();
|
|
|
|
|
|
|
|
av_start_time = av_end_time = -1;
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsConsumer::SrsConsumer(SrsSource* _source)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
source = _source;
|
|
|
|
paused = false;
|
|
|
|
jitter = new SrsRtmpJitter();
|
|
|
|
queue = new SrsMessageQueue();
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsConsumer::~SrsConsumer()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
source->on_consumer_destroy(this);
|
|
|
|
srs_freep(jitter);
|
|
|
|
srs_freep(queue);
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsConsumer::set_queue_size(double queue_size)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
queue->set_queue_size(queue_size);
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsConsumer::get_time()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return jitter->get_time();
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
int SrsConsumer::enqueue(SrsSharedPtrMessage* msg, int tba, int tbv)
|
2013-12-15 10:25:55 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-03-26 08:25:02 +00:00
|
|
|
if (!source->is_atc()) {
|
|
|
|
if ((ret = jitter->correct(msg, tba, tbv)) != ERROR_SUCCESS) {
|
|
|
|
srs_freep(msg);
|
|
|
|
return ret;
|
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = queue->enqueue(msg)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
int SrsConsumer::get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& count)
|
2013-12-15 10:25:55 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
// paused, return nothing.
|
|
|
|
if (paused) {
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return queue->get_packets(max_count, pmsgs, count);
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsConsumer::on_play_client_pause(bool is_pause)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
srs_trace("stream consumer change pause state %d=>%d", paused, is_pause);
|
|
|
|
paused = is_pause;
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsGopCache::SrsGopCache()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
cached_video_count = 0;
|
|
|
|
enable_gop_cache = true;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsGopCache::~SrsGopCache()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
clear();
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsGopCache::set(bool enabled)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
enable_gop_cache = enabled;
|
|
|
|
|
|
|
|
if (!enabled) {
|
|
|
|
srs_info("disable gop cache, clear %d packets.", (int)gop_cache.size());
|
|
|
|
clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_info("enable gop cache");
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
int SrsGopCache::cache(SrsSharedPtrMessage* msg)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
if (!enable_gop_cache) {
|
|
|
|
srs_verbose("gop cache is disabled.");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// got video, update the video count if acceptable
|
|
|
|
if (msg->header.is_video()) {
|
|
|
|
cached_video_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// no acceptable video or pure audio, disable the cache.
|
|
|
|
if (cached_video_count == 0) {
|
|
|
|
srs_verbose("ignore any frame util got a h264 video frame.");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// clear gop cache when got key frame
|
|
|
|
if (msg->header.is_video() && SrsCodec::video_is_keyframe(msg->payload, msg->size)) {
|
|
|
|
srs_info("clear gop cache when got keyframe. vcount=%d, count=%d",
|
|
|
|
cached_video_count, (int)gop_cache.size());
|
|
|
|
|
|
|
|
clear();
|
|
|
|
|
|
|
|
// curent msg is video frame, so we set to 1.
|
|
|
|
cached_video_count = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// cache the frame.
|
|
|
|
gop_cache.push_back(msg->copy());
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsGopCache::clear()
|
|
|
|
{
|
2014-04-29 06:44:07 +00:00
|
|
|
std::vector<SrsSharedPtrMessage*>::iterator it;
|
2014-03-18 03:32:58 +00:00
|
|
|
for (it = gop_cache.begin(); it != gop_cache.end(); ++it) {
|
2014-04-29 06:44:07 +00:00
|
|
|
SrsSharedPtrMessage* msg = *it;
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(msg);
|
|
|
|
}
|
|
|
|
gop_cache.clear();
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
cached_video_count = 0;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2013-12-14 06:06:32 +00:00
|
|
|
int SrsGopCache::dump(SrsConsumer* consumer, int tba, int tbv)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
std::vector<SrsSharedPtrMessage*>::iterator it;
|
2014-03-18 03:32:58 +00:00
|
|
|
for (it = gop_cache.begin(); it != gop_cache.end(); ++it) {
|
2014-04-29 06:44:07 +00:00
|
|
|
SrsSharedPtrMessage* msg = *it;
|
2014-03-18 03:32:58 +00:00
|
|
|
if ((ret = consumer->enqueue(msg->copy(), tba, tbv)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dispatch cached gop failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
srs_trace("dispatch cached gop success. count=%d, duration=%d", (int)gop_cache.size(), consumer->get_time());
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-03-26 08:25:02 +00:00
|
|
|
bool SrsGopCache::empty()
|
|
|
|
{
|
|
|
|
return gop_cache.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t SrsGopCache::get_start_time()
|
|
|
|
{
|
|
|
|
if (empty()) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
SrsSharedPtrMessage* msg = gop_cache[0];
|
2014-03-26 08:25:02 +00:00
|
|
|
srs_assert(msg);
|
|
|
|
|
|
|
|
return msg->header.timestamp;
|
|
|
|
}
|
|
|
|
|
2013-12-14 06:06:32 +00:00
|
|
|
std::map<std::string, SrsSource*> SrsSource::pool;
|
|
|
|
|
2014-04-17 08:57:04 +00:00
|
|
|
int SrsSource::find(SrsRequest* req, SrsSource** ppsource)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-04-17 08:57:04 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
string stream_url = req->get_stream_url();
|
|
|
|
string vhost = req->vhost;
|
|
|
|
|
|
|
|
if (pool.find(stream_url) == pool.end()) {
|
2014-04-17 08:57:04 +00:00
|
|
|
SrsSource* source = new SrsSource(req);
|
|
|
|
if ((ret = source->initialize()) != ERROR_SUCCESS) {
|
|
|
|
srs_freep(source);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
pool[stream_url] = source;
|
2014-04-11 06:13:14 +00:00
|
|
|
srs_info("create new source for url=%s, vhost=%s", stream_url.c_str(), vhost.c_str());
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2014-04-17 08:57:04 +00:00
|
|
|
*ppsource = pool[stream_url];
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-05-03 14:59:21 +00:00
|
|
|
void SrsSource::destroy()
|
|
|
|
{
|
|
|
|
std::map<std::string, SrsSource*>::iterator it;
|
|
|
|
for (it = pool.begin(); it != pool.end(); ++it) {
|
|
|
|
SrsSource* source = it->second;
|
|
|
|
srs_freep(source);
|
|
|
|
}
|
|
|
|
pool.clear();
|
|
|
|
}
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
SrsSource::SrsSource(SrsRequest* req)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-04-26 09:16:18 +00:00
|
|
|
_req = req->copy();
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-03-18 03:32:58 +00:00
|
|
|
hls = new SrsHls(this);
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-04-16 01:28:02 +00:00
|
|
|
#ifdef SRS_AUTO_DVR
|
|
|
|
dvr = new SrsDvr(this);
|
|
|
|
#endif
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_TRANSCODE
|
2014-03-18 03:32:58 +00:00
|
|
|
encoder = new SrsEncoder();
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
cache_metadata = cache_sh_video = cache_sh_audio = NULL;
|
|
|
|
|
|
|
|
frame_rate = sample_rate = 0;
|
|
|
|
_can_publish = true;
|
|
|
|
|
2014-04-27 01:29:37 +00:00
|
|
|
play_edge = new SrsPlayEdge();
|
|
|
|
publish_edge = new SrsPublishEdge();
|
2014-03-18 03:32:58 +00:00
|
|
|
gop_cache = new SrsGopCache();
|
|
|
|
|
|
|
|
_srs_config->subscribe(this);
|
2014-04-26 09:16:18 +00:00
|
|
|
atc = _srs_config->get_atc(_req->vhost);
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsSource::~SrsSource()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
_srs_config->unsubscribe(this);
|
|
|
|
|
2014-05-03 14:59:21 +00:00
|
|
|
// never free the consumers,
|
|
|
|
// for all consumers are auto free.
|
|
|
|
consumers.clear();
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
|
|
|
srs_freep(forwarder);
|
|
|
|
}
|
|
|
|
forwarders.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_freep(cache_metadata);
|
|
|
|
srs_freep(cache_sh_video);
|
|
|
|
srs_freep(cache_sh_audio);
|
|
|
|
|
2014-04-27 01:29:37 +00:00
|
|
|
srs_freep(play_edge);
|
|
|
|
srs_freep(publish_edge);
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(gop_cache);
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(hls);
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-04-16 01:28:02 +00:00
|
|
|
#ifdef SRS_AUTO_DVR
|
|
|
|
srs_freep(dvr);
|
|
|
|
#endif
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_TRANSCODE
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(encoder);
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2013-12-15 04:34:22 +00:00
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
srs_freep(_req);
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-17 08:57:04 +00:00
|
|
|
int SrsSource::initialize()
|
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
#ifdef SRS_AUTO_DVR
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = dvr->initialize(_req)) != ERROR_SUCCESS) {
|
2014-04-17 08:57:04 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|
2014-04-26 09:16:18 +00:00
|
|
|
|
2014-04-27 01:29:37 +00:00
|
|
|
if ((ret = play_edge->initialize(this, _req)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if ((ret = publish_edge->initialize(this, _req)) != ERROR_SUCCESS) {
|
2014-04-26 09:16:18 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2014-04-17 08:57:04 +00:00
|
|
|
|
2014-04-28 09:20:35 +00:00
|
|
|
double queue_size = _srs_config->get_queue_length(_req->vhost);
|
|
|
|
publish_edge->set_queue_size(queue_size);
|
|
|
|
|
2014-04-17 08:57:04 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-13 05:31:59 +00:00
|
|
|
int SrsSource::on_reload_vhost_atc(string vhost)
|
2014-04-12 14:00:27 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
if (_req->vhost != vhost) {
|
2014-04-12 14:00:27 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// atc changed.
|
|
|
|
bool enabled_atc = _srs_config->get_atc(vhost);
|
|
|
|
|
|
|
|
srs_warn("vhost %s atc changed to %d, connected client may corrupt.",
|
|
|
|
vhost.c_str(), enabled_atc);
|
|
|
|
|
|
|
|
gop_cache->clear();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-13 05:31:59 +00:00
|
|
|
int SrsSource::on_reload_vhost_gop_cache(string vhost)
|
2013-12-15 04:04:28 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
if (_req->vhost != vhost) {
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// gop cache changed.
|
|
|
|
bool enabled_cache = _srs_config->get_gop_cache(vhost);
|
|
|
|
|
|
|
|
srs_trace("vhost %s gop_cache changed to %d, source url=%s",
|
2014-04-26 09:16:18 +00:00
|
|
|
vhost.c_str(), enabled_cache, _req->get_stream_url().c_str());
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
set_cache(enabled_cache);
|
|
|
|
|
|
|
|
return ret;
|
2013-12-15 04:04:28 +00:00
|
|
|
}
|
|
|
|
|
2014-04-13 05:31:59 +00:00
|
|
|
int SrsSource::on_reload_vhost_queue_length(string vhost)
|
2013-12-15 10:25:55 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
if (_req->vhost != vhost) {
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
double queue_size = _srs_config->get_queue_length(_req->vhost);
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsConsumer*>::iterator it;
|
|
|
|
|
|
|
|
for (it = consumers.begin(); it != consumers.end(); ++it) {
|
|
|
|
SrsConsumer* consumer = *it;
|
|
|
|
consumer->set_queue_size(queue_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_trace("consumers reload queue size success.");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
|
|
|
forwarder->set_queue_size(queue_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_trace("forwarders reload queue size success.");
|
|
|
|
}
|
|
|
|
|
2014-04-28 09:20:35 +00:00
|
|
|
if (true) {
|
|
|
|
publish_edge->set_queue_size(queue_size);
|
|
|
|
srs_trace("publish_edge reload queue size success.");
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
2014-04-13 05:31:59 +00:00
|
|
|
int SrsSource::on_reload_vhost_forward(string vhost)
|
2013-12-15 04:34:22 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
if (_req->vhost != vhost) {
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2013-12-15 04:34:22 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// forwarders
|
|
|
|
destroy_forwarders();
|
|
|
|
if ((ret = create_forwarders()) != ERROR_SUCCESS) {
|
|
|
|
srs_error("create forwarders failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2013-12-15 09:09:25 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_trace("vhost %s forwarders reload success", vhost.c_str());
|
|
|
|
|
|
|
|
return ret;
|
2013-12-15 04:34:22 +00:00
|
|
|
}
|
|
|
|
|
2014-04-13 05:31:59 +00:00
|
|
|
int SrsSource::on_reload_vhost_hls(string vhost)
|
2013-12-15 05:07:39 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
if (_req->vhost != vhost) {
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-03-18 03:32:58 +00:00
|
|
|
hls->on_unpublish();
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = hls->on_publish(_req)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("hls publish failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_trace("vhost %s hls reload success", vhost.c_str());
|
2013-12-15 05:07:39 +00:00
|
|
|
#endif
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
return ret;
|
2013-12-15 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2014-04-17 08:22:21 +00:00
|
|
|
int SrsSource::on_reload_vhost_dvr(string vhost)
|
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
if (_req->vhost != vhost) {
|
2014-04-17 08:22:21 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef SRS_AUTO_DVR
|
2014-04-17 08:57:04 +00:00
|
|
|
// cleanup dvr
|
2014-04-17 08:22:21 +00:00
|
|
|
dvr->on_unpublish();
|
2014-04-17 08:57:04 +00:00
|
|
|
|
|
|
|
// reinitialize the dvr, update plan.
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = dvr->initialize(_req)) != ERROR_SUCCESS) {
|
2014-04-17 08:57:04 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// start to publish by new plan.
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = dvr->on_publish(_req)) != ERROR_SUCCESS) {
|
2014-04-17 08:22:21 +00:00
|
|
|
srs_error("dvr publish failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2014-04-17 08:57:04 +00:00
|
|
|
|
2014-04-17 08:22:21 +00:00
|
|
|
srs_trace("vhost %s dvr reload success", vhost.c_str());
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-13 05:31:59 +00:00
|
|
|
int SrsSource::on_reload_vhost_transcode(string vhost)
|
2013-12-15 05:07:39 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
if (_req->vhost != vhost) {
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_TRANSCODE
|
2014-03-18 03:32:58 +00:00
|
|
|
encoder->on_unpublish();
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = encoder->on_publish(_req)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("start encoder failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_trace("vhost %s transcode reload success", vhost.c_str());
|
2013-12-15 05:07:39 +00:00
|
|
|
#endif
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
return ret;
|
2013-12-15 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 09:09:25 +00:00
|
|
|
int SrsSource::on_forwarder_start(SrsForwarder* forwarder)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// feed the forwarder the metadata/sequence header,
|
|
|
|
// when reload to enable the forwarder.
|
|
|
|
if (cache_metadata && (ret = forwarder->on_meta_data(cache_metadata->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("forwarder process onMetaData message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (cache_sh_video && (ret = forwarder->on_video(cache_sh_video->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("forwarder process video sequence header message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (cache_sh_audio && (ret = forwarder->on_audio(cache_sh_audio->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("forwarder process audio sequence header message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-15 09:09:25 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 12:29:18 +00:00
|
|
|
int SrsSource::on_hls_start()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-03-18 03:32:58 +00:00
|
|
|
// feed the hls the metadata/sequence header,
|
2014-04-16 03:11:53 +00:00
|
|
|
// when reload to start hls, hls will never get the sequence header in stream,
|
|
|
|
// use the SrsSource.on_hls_start to push the sequence header to HLS.
|
2014-03-18 03:32:58 +00:00
|
|
|
// TODO: maybe need to decode the metadata?
|
|
|
|
if (cache_sh_video && (ret = hls->on_video(cache_sh_video->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("hls process video sequence header message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (cache_sh_audio && (ret = hls->on_audio(cache_sh_audio->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("hls process audio sequence header message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2014-04-17 08:06:49 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-24 08:32:19 +00:00
|
|
|
int SrsSource::on_dvr_request_sh()
|
2014-04-17 08:06:49 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
#ifdef SRS_AUTO_DVR
|
|
|
|
// feed the dvr the metadata/sequence header,
|
|
|
|
// when reload to start dvr, dvr will never get the sequence header in stream,
|
2014-04-24 08:32:19 +00:00
|
|
|
// use the SrsSource.on_dvr_request_sh to push the sequence header to DVR.
|
2014-04-17 08:06:49 +00:00
|
|
|
if (cache_metadata) {
|
|
|
|
char* payload = (char*)cache_metadata->payload;
|
|
|
|
int size = (int)cache_metadata->size;
|
|
|
|
|
|
|
|
SrsStream stream;
|
|
|
|
if ((ret = stream.initialize(payload, size)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dvr decode metadata stream failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsOnMetaDataPacket pkt;
|
|
|
|
if ((ret = pkt.decode(&stream)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dvr decode metadata packet failed.");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = dvr->on_meta_data(&pkt)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dvr process onMetaData message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-04-17 08:06:49 +00:00
|
|
|
if (cache_sh_video && (ret = dvr->on_video(cache_sh_video->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dvr process video sequence header message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (cache_sh_audio && (ret = dvr->on_audio(cache_sh_audio->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dvr process audio sequence header message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2013-12-15 12:29:18 +00:00
|
|
|
#endif
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
return ret;
|
2013-12-15 12:29:18 +00:00
|
|
|
}
|
|
|
|
|
2013-12-14 06:06:32 +00:00
|
|
|
bool SrsSource::can_publish()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return _can_publish;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
int SrsSource::on_meta_data(SrsMessage* msg, SrsOnMetaDataPacket* metadata)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-03-18 03:32:58 +00:00
|
|
|
if (metadata && (ret = hls->on_meta_data(metadata->metadata)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("hls process onMetaData message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-04-16 01:28:02 +00:00
|
|
|
#ifdef SRS_AUTO_DVR
|
2014-04-17 08:06:49 +00:00
|
|
|
if (metadata && (ret = dvr->on_meta_data(metadata)) != ERROR_SUCCESS) {
|
2014-04-16 01:28:02 +00:00
|
|
|
srs_error("dvr process onMetaData message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
metadata->metadata->set("server", SrsAmf0Any::str(RTMP_SIG_SRS_KEY" "RTMP_SIG_SRS_VERSION" ("RTMP_SIG_SRS_URL_SHORT")"));
|
|
|
|
metadata->metadata->set("contributor", SrsAmf0Any::str(RTMP_SIG_SRS_PRIMARY_AUTHROS));
|
|
|
|
|
|
|
|
SrsAmf0Any* prop = NULL;
|
|
|
|
if ((prop = metadata->metadata->get_property("audiosamplerate")) != NULL) {
|
|
|
|
if (prop->is_number()) {
|
|
|
|
sample_rate = (int)prop->to_number();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((prop = metadata->metadata->get_property("framerate")) != NULL) {
|
|
|
|
if (prop->is_number()) {
|
|
|
|
frame_rate = (int)prop->to_number();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-30 04:08:11 +00:00
|
|
|
// if allow atc_auto and bravo-atc detected, open atc for vhost.
|
2014-04-30 02:31:05 +00:00
|
|
|
atc = _srs_config->get_atc(_req->vhost);
|
2014-04-30 04:08:11 +00:00
|
|
|
if (_srs_config->get_atc_auto(_req->vhost)) {
|
|
|
|
if ((prop = metadata->metadata->get_property("bravo_atc")) != NULL) {
|
|
|
|
if (prop->is_string() && prop->to_str() == "true") {
|
|
|
|
atc = true;
|
|
|
|
}
|
2014-04-29 10:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// encode the metadata to payload
|
2014-04-29 06:44:07 +00:00
|
|
|
int size = 0;
|
2014-03-18 03:32:58 +00:00
|
|
|
char* payload = NULL;
|
|
|
|
if ((ret = metadata->encode(size, payload)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("encode metadata error. ret=%d", ret);
|
|
|
|
srs_freepa(payload);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("encode metadata success.");
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
if (size <= 0) {
|
|
|
|
srs_warn("ignore the invalid metadata. size=%d", size);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// create a shared ptr message.
|
|
|
|
srs_freep(cache_metadata);
|
2014-04-29 06:44:07 +00:00
|
|
|
cache_metadata = new SrsSharedPtrMessage();
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
// dump message to shared ptr message.
|
|
|
|
if ((ret = cache_metadata->initialize(&msg->header, payload, size)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("initialize the cache metadata failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("initialize shared ptr metadata success.");
|
|
|
|
|
|
|
|
// copy to all consumer
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsConsumer*>::iterator it;
|
|
|
|
for (it = consumers.begin(); it != consumers.end(); ++it) {
|
|
|
|
SrsConsumer* consumer = *it;
|
|
|
|
if ((ret = consumer->enqueue(cache_metadata->copy(), sample_rate, frame_rate)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dispatch the metadata failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
srs_trace("dispatch metadata success.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// copy to all forwarders
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
|
|
|
if ((ret = forwarder->on_meta_data(cache_metadata->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("forwarder process onMetaData message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
int SrsSource::on_audio(SrsMessage* audio)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
SrsSharedPtrMessage* msg = new SrsSharedPtrMessage();
|
|
|
|
SrsAutoFree(SrsSharedPtrMessage, msg, false);
|
2014-03-18 03:32:58 +00:00
|
|
|
if ((ret = msg->initialize(audio)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("initialize the audio failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("initialize shared ptr audio success.");
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-03-18 03:32:58 +00:00
|
|
|
if ((ret = hls->on_audio(msg->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_warn("hls process audio message failed, ignore and disable hls. ret=%d", ret);
|
|
|
|
|
|
|
|
// unpublish, ignore ret.
|
|
|
|
hls->on_unpublish();
|
|
|
|
|
|
|
|
// ignore.
|
|
|
|
ret = ERROR_SUCCESS;
|
|
|
|
}
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-04-16 01:28:02 +00:00
|
|
|
#ifdef SRS_AUTO_DVR
|
|
|
|
if ((ret = dvr->on_audio(msg->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_warn("dvr process audio message failed, ignore and disable dvr. ret=%d", ret);
|
|
|
|
|
|
|
|
// unpublish, ignore ret.
|
|
|
|
dvr->on_unpublish();
|
|
|
|
|
|
|
|
// ignore.
|
|
|
|
ret = ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// copy to all consumer
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsConsumer*>::iterator it;
|
|
|
|
for (it = consumers.begin(); it != consumers.end(); ++it) {
|
|
|
|
SrsConsumer* consumer = *it;
|
|
|
|
if ((ret = consumer->enqueue(msg->copy(), sample_rate, frame_rate)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dispatch the audio failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
srs_info("dispatch audio success.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// copy to all forwarders.
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
|
|
|
if ((ret = forwarder->on_audio(msg->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("forwarder process audio message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// cache the sequence header if h264
|
|
|
|
if (SrsCodec::audio_is_sequence_header(msg->payload, msg->size)) {
|
|
|
|
srs_freep(cache_sh_audio);
|
|
|
|
cache_sh_audio = msg->copy();
|
|
|
|
srs_trace("update audio sequence header success. size=%d", msg->header.payload_length);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// cache the last gop packets
|
|
|
|
if ((ret = gop_cache->cache(msg)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("shrink gop cache failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("cache gop success.");
|
|
|
|
|
2014-03-26 08:25:02 +00:00
|
|
|
// if atc, update the sequence header to abs time.
|
|
|
|
if (atc) {
|
|
|
|
if (cache_sh_audio) {
|
|
|
|
cache_sh_audio->header.timestamp = msg->header.timestamp;
|
|
|
|
}
|
|
|
|
if (cache_metadata) {
|
|
|
|
cache_metadata->header.timestamp = msg->header.timestamp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
int SrsSource::on_video(SrsMessage* video)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
SrsSharedPtrMessage* msg = new SrsSharedPtrMessage();
|
|
|
|
SrsAutoFree(SrsSharedPtrMessage, msg, false);
|
2014-03-18 03:32:58 +00:00
|
|
|
if ((ret = msg->initialize(video)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("initialize the video failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("initialize shared ptr video success.");
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-03-18 03:32:58 +00:00
|
|
|
if ((ret = hls->on_video(msg->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_warn("hls process video message failed, ignore and disable hls. ret=%d", ret);
|
|
|
|
|
|
|
|
// unpublish, ignore ret.
|
|
|
|
hls->on_unpublish();
|
|
|
|
|
|
|
|
// ignore.
|
|
|
|
ret = ERROR_SUCCESS;
|
|
|
|
}
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-04-16 01:28:02 +00:00
|
|
|
#ifdef SRS_AUTO_DVR
|
|
|
|
if ((ret = dvr->on_video(msg->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_warn("dvr process video message failed, ignore and disable dvr. ret=%d", ret);
|
|
|
|
|
|
|
|
// unpublish, ignore ret.
|
|
|
|
dvr->on_unpublish();
|
|
|
|
|
|
|
|
// ignore.
|
|
|
|
ret = ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// copy to all consumer
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsConsumer*>::iterator it;
|
|
|
|
for (it = consumers.begin(); it != consumers.end(); ++it) {
|
|
|
|
SrsConsumer* consumer = *it;
|
|
|
|
if ((ret = consumer->enqueue(msg->copy(), sample_rate, frame_rate)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dispatch the video failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
srs_info("dispatch video success.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// copy to all forwarders.
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
|
|
|
if ((ret = forwarder->on_video(msg->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("forwarder process video message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// cache the sequence header if h264
|
|
|
|
if (SrsCodec::video_is_sequence_header(msg->payload, msg->size)) {
|
|
|
|
srs_freep(cache_sh_video);
|
|
|
|
cache_sh_video = msg->copy();
|
|
|
|
srs_trace("update video sequence header success. size=%d", msg->header.payload_length);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// cache the last gop packets
|
|
|
|
if ((ret = gop_cache->cache(msg)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("gop cache msg failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("cache gop success.");
|
|
|
|
|
2014-03-26 08:25:02 +00:00
|
|
|
// if atc, update the sequence header to abs time.
|
|
|
|
if (atc) {
|
|
|
|
if (cache_sh_video) {
|
|
|
|
cache_sh_video->header.timestamp = msg->header.timestamp;
|
|
|
|
}
|
|
|
|
if (cache_metadata) {
|
|
|
|
cache_metadata->header.timestamp = msg->header.timestamp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
int SrsSource::on_publish()
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// update the request object.
|
2014-04-26 09:16:18 +00:00
|
|
|
srs_assert(_req);
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
_can_publish = false;
|
|
|
|
|
|
|
|
// create forwarders
|
|
|
|
if ((ret = create_forwarders()) != ERROR_SUCCESS) {
|
|
|
|
srs_error("create forwarders failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_TRANSCODE
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = encoder->on_publish(_req)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("start encoder failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = hls->on_publish(_req)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("start hls failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-04-16 01:28:02 +00:00
|
|
|
|
|
|
|
#ifdef SRS_AUTO_DVR
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = dvr->on_publish(_req)) != ERROR_SUCCESS) {
|
2014-04-16 01:28:02 +00:00
|
|
|
srs_error("start dvr failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsSource::on_unpublish()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
// destroy all forwarders
|
|
|
|
destroy_forwarders();
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_TRANSCODE
|
2014-03-18 03:32:58 +00:00
|
|
|
encoder->on_unpublish();
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-03-18 03:32:58 +00:00
|
|
|
hls->on_unpublish();
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-04-16 01:28:02 +00:00
|
|
|
|
|
|
|
#ifdef SRS_AUTO_DVR
|
|
|
|
dvr->on_unpublish();
|
|
|
|
#endif
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
gop_cache->clear();
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(cache_metadata);
|
|
|
|
frame_rate = sample_rate = 0;
|
|
|
|
|
|
|
|
srs_freep(cache_sh_video);
|
|
|
|
srs_freep(cache_sh_audio);
|
|
|
|
|
|
|
|
srs_trace("clear cache/metadata/sequence-headers when unpublish.");
|
|
|
|
|
|
|
|
_can_publish = true;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsSource::create_consumer(SrsConsumer*& consumer)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
consumer = new SrsConsumer(this);
|
|
|
|
consumers.push_back(consumer);
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
double queue_size = _srs_config->get_queue_length(_req->vhost);
|
2014-03-18 03:32:58 +00:00
|
|
|
consumer->set_queue_size(queue_size);
|
|
|
|
|
|
|
|
if (cache_metadata && (ret = consumer->enqueue(cache_metadata->copy(), sample_rate, frame_rate)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dispatch metadata failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_info("dispatch metadata success");
|
|
|
|
|
2014-03-26 08:25:02 +00:00
|
|
|
// if atc, update the sequence header to gop cache time.
|
|
|
|
if (atc && !gop_cache->empty()) {
|
|
|
|
if (cache_sh_video) {
|
|
|
|
cache_sh_video->header.timestamp = gop_cache->get_start_time();
|
|
|
|
}
|
|
|
|
if (cache_sh_audio) {
|
|
|
|
cache_sh_audio->header.timestamp = gop_cache->get_start_time();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// copy sequence header
|
2014-03-18 03:32:58 +00:00
|
|
|
if (cache_sh_video && (ret = consumer->enqueue(cache_sh_video->copy(), sample_rate, frame_rate)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dispatch video sequence header failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_info("dispatch video sequence header success");
|
|
|
|
|
|
|
|
if (cache_sh_audio && (ret = consumer->enqueue(cache_sh_audio->copy(), sample_rate, frame_rate)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dispatch audio sequence header failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_info("dispatch audio sequence header success");
|
|
|
|
|
2014-03-26 08:25:02 +00:00
|
|
|
// copy gop cache to client.
|
2014-03-18 03:32:58 +00:00
|
|
|
if ((ret = gop_cache->dump(consumer, sample_rate, frame_rate)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_trace("create consumer, queue_size=%.2f, tba=%d, tbv=%d", queue_size, sample_rate, frame_rate);
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsSource::on_consumer_destroy(SrsConsumer* consumer)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
std::vector<SrsConsumer*>::iterator it;
|
|
|
|
it = std::find(consumers.begin(), consumers.end(), consumer);
|
|
|
|
if (it != consumers.end()) {
|
|
|
|
consumers.erase(it);
|
|
|
|
}
|
|
|
|
srs_info("handle consumer destroy success.");
|
2014-04-26 13:41:18 +00:00
|
|
|
|
|
|
|
if (consumers.empty()) {
|
2014-04-27 01:29:37 +00:00
|
|
|
play_edge->on_all_client_stop();
|
2014-04-26 13:41:18 +00:00
|
|
|
}
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsSource::set_cache(bool enabled)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
gop_cache->set(enabled);
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-03-26 08:25:02 +00:00
|
|
|
bool SrsSource::is_atc()
|
|
|
|
{
|
|
|
|
return atc;
|
|
|
|
}
|
|
|
|
|
2014-04-26 13:41:18 +00:00
|
|
|
int SrsSource::on_edge_start_play()
|
2014-04-25 08:35:03 +00:00
|
|
|
{
|
2014-04-27 01:29:37 +00:00
|
|
|
return play_edge->on_client_play();
|
|
|
|
}
|
|
|
|
|
|
|
|
int SrsSource::on_edge_start_publish()
|
|
|
|
{
|
|
|
|
return publish_edge->on_client_publish();
|
2014-04-25 08:35:03 +00:00
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
int SrsSource::on_edge_proxy_publish(SrsMessage* msg)
|
2014-04-27 03:11:15 +00:00
|
|
|
{
|
2014-04-27 06:57:28 +00:00
|
|
|
return publish_edge->on_proxy_publish(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsSource::on_edge_proxy_unpublish()
|
|
|
|
{
|
|
|
|
publish_edge->on_proxy_unpublish();
|
2014-04-27 03:11:15 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 04:34:22 +00:00
|
|
|
int SrsSource::create_forwarders()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
SrsConfDirective* conf = _srs_config->get_forward(_req->vhost);
|
2014-03-18 03:32:58 +00:00
|
|
|
for (int i = 0; conf && i < (int)conf->args.size(); i++) {
|
|
|
|
std::string forward_server = conf->args.at(i);
|
|
|
|
|
|
|
|
SrsForwarder* forwarder = new SrsForwarder(this);
|
|
|
|
forwarders.push_back(forwarder);
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
double queue_size = _srs_config->get_queue_length(_req->vhost);
|
2014-03-18 03:32:58 +00:00
|
|
|
forwarder->set_queue_size(queue_size);
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = forwarder->on_publish(_req, forward_server)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("start forwarder failed. "
|
|
|
|
"vhost=%s, app=%s, stream=%s, forward-to=%s",
|
2014-04-26 09:16:18 +00:00
|
|
|
_req->vhost.c_str(), _req->app.c_str(), _req->stream.c_str(),
|
2014-03-18 03:32:58 +00:00
|
|
|
forward_server.c_str());
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-15 04:34:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsSource::destroy_forwarders()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
|
|
|
forwarder->on_unpublish();
|
|
|
|
srs_freep(forwarder);
|
|
|
|
}
|
|
|
|
forwarders.clear();
|
2013-12-15 04:34:22 +00:00
|
|
|
}
|
|
|
|
|