2017-03-25 09:21:39 +00:00
|
|
|
/**
|
|
|
|
* The MIT License (MIT)
|
|
|
|
*
|
2019-12-30 02:10:35 +00:00
|
|
|
* Copyright (c) 2013-2020 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.
|
|
|
|
*/
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-03-02 13:49:09 +00:00
|
|
|
#include <srs_app_source.hpp>
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-05-29 06:16:34 +00:00
|
|
|
#include <sstream>
|
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>
|
2015-01-23 02:07:20 +00:00
|
|
|
#include <srs_rtmp_stack.hpp>
|
2015-09-22 01:05:21 +00:00
|
|
|
#include <srs_protocol_amf0.hpp>
|
2014-05-28 09:37:15 +00:00
|
|
|
#include <srs_kernel_codec.hpp>
|
2020-05-11 04:07:55 +00:00
|
|
|
#include <srs_kernel_rtc_rtp.hpp>
|
2014-03-02 13:49:09 +00:00
|
|
|
#include <srs_app_hls.hpp>
|
|
|
|
#include <srs_app_forward.hpp>
|
|
|
|
#include <srs_app_config.hpp>
|
|
|
|
#include <srs_app_encoder.hpp>
|
2015-06-13 08:04:59 +00:00
|
|
|
#include <srs_rtmp_stack.hpp>
|
2014-04-16 01:28:02 +00:00
|
|
|
#include <srs_app_dvr.hpp>
|
2015-09-22 00:48:55 +00:00
|
|
|
#include <srs_kernel_buffer.hpp>
|
2014-04-26 06:47:38 +00:00
|
|
|
#include <srs_app_edge.hpp>
|
2014-06-08 05:03:03 +00:00
|
|
|
#include <srs_kernel_utility.hpp>
|
2015-01-31 13:16:42 +00:00
|
|
|
#include <srs_kernel_codec.hpp>
|
2015-01-23 02:07:20 +00:00
|
|
|
#include <srs_rtmp_msg_array.hpp>
|
2015-03-11 05:34:58 +00:00
|
|
|
#include <srs_app_hds.hpp>
|
2015-03-08 07:33:08 +00:00
|
|
|
#include <srs_app_statistic.hpp>
|
2015-04-15 09:12:22 +00:00
|
|
|
#include <srs_core_autofree.hpp>
|
2015-09-22 01:11:07 +00:00
|
|
|
#include <srs_protocol_utility.hpp>
|
2015-08-25 14:29:00 +00:00
|
|
|
#include <srs_app_ng_exec.hpp>
|
2017-02-11 13:14:28 +00:00
|
|
|
#include <srs_app_dash.hpp>
|
2017-02-11 15:09:23 +00:00
|
|
|
#include <srs_protocol_format.hpp>
|
2020-05-12 11:53:21 +00:00
|
|
|
#include <srs_app_rtc_source.hpp>
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2015-06-10 07:38:13 +00:00
|
|
|
#define CONST_MAX_JITTER_MS 250
|
|
|
|
#define CONST_MAX_JITTER_MS_NEG -250
|
|
|
|
#define DEFAULT_FRAME_TIME_MS 10
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-07-26 04:22:39 +00:00
|
|
|
// for 26ms per audio packet,
|
|
|
|
// 115 packets is 3s.
|
2015-03-21 03:55:28 +00:00
|
|
|
#define SRS_PURE_AUDIO_GUESS_COUNT 115
|
2014-07-26 04:22:39 +00:00
|
|
|
|
2015-07-14 03:28:00 +00:00
|
|
|
// when got these videos or audios, pure audio or video, mix ok.
|
|
|
|
#define SRS_MIX_CORRECT_PURE_AV 10
|
2015-06-06 13:54:43 +00:00
|
|
|
|
2019-04-10 01:07:03 +00:00
|
|
|
// the time to cleanup source.
|
|
|
|
#define SRS_SOURCE_CLEANUP (30 * SRS_UTIME_SECONDS)
|
2016-09-05 06:13:37 +00:00
|
|
|
|
2020-10-31 09:53:00 +00:00
|
|
|
int srs_time_jitter_string2int(std::string time_jitter)
|
2014-06-25 09:14:11 +00:00
|
|
|
{
|
|
|
|
if (time_jitter == "full") {
|
|
|
|
return SrsRtmpJitterAlgorithmFULL;
|
|
|
|
} else if (time_jitter == "zero") {
|
|
|
|
return SrsRtmpJitterAlgorithmZERO;
|
|
|
|
} else {
|
|
|
|
return SrsRtmpJitterAlgorithmOFF;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-14 06:06:32 +00:00
|
|
|
SrsRtmpJitter::SrsRtmpJitter()
|
|
|
|
{
|
2015-06-10 07:38:13 +00:00
|
|
|
last_pkt_correct_time = -1;
|
|
|
|
last_pkt_time = 0;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsRtmpJitter::~SrsRtmpJitter()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-09-22 13:50:54 +00:00
|
|
|
srs_error_t SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, SrsRtmpJitterAlgorithm ag)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2017-09-22 13:50:54 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-06-25 09:14:11 +00:00
|
|
|
|
2014-06-26 02:13:43 +00:00
|
|
|
// for performance issue
|
|
|
|
if (ag != SrsRtmpJitterAlgorithmFULL) {
|
|
|
|
// all jitter correct features is disabled, ignore.
|
|
|
|
if (ag == SrsRtmpJitterAlgorithmOFF) {
|
2017-09-22 13:50:54 +00:00
|
|
|
return err;
|
2014-06-26 02:13:43 +00:00
|
|
|
}
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2014-06-26 02:13:43 +00:00
|
|
|
// start at zero, but donot ensure monotonically increasing.
|
|
|
|
if (ag == SrsRtmpJitterAlgorithmZERO) {
|
2015-06-10 07:38:13 +00:00
|
|
|
// for the first time, last_pkt_correct_time is -1.
|
|
|
|
if (last_pkt_correct_time == -1) {
|
2014-12-07 03:25:05 +00:00
|
|
|
last_pkt_correct_time = msg->timestamp;
|
2014-06-26 02:13:43 +00:00
|
|
|
}
|
2014-12-07 03:25:05 +00:00
|
|
|
msg->timestamp -= last_pkt_correct_time;
|
2017-09-22 13:50:54 +00:00
|
|
|
return err;
|
2014-06-25 09:14:11 +00:00
|
|
|
}
|
2014-06-26 02:13:43 +00:00
|
|
|
|
|
|
|
// other algorithm, ignore.
|
2017-09-22 13:50:54 +00:00
|
|
|
return err;
|
2014-06-25 09:14:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// full jitter algorithm, do jitter correct.
|
2014-03-18 03:32:58 +00:00
|
|
|
// set to 0 for metadata.
|
2014-12-07 03:25:05 +00:00
|
|
|
if (!msg->is_av()) {
|
|
|
|
msg->timestamp = 0;
|
2017-09-22 13:50:54 +00:00
|
|
|
return err;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-03-25 09:21:39 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
2014-12-07 03:25:05 +00:00
|
|
|
int64_t time = msg->timestamp;
|
2014-03-18 03:32:58 +00:00
|
|
|
int64_t delta = time - last_pkt_time;
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// if jitter detected, reset the delta.
|
2015-06-10 07:38:13 +00:00
|
|
|
if (delta < CONST_MAX_JITTER_MS_NEG || delta > CONST_MAX_JITTER_MS) {
|
|
|
|
// use default 10ms to notice the problem of stream.
|
2015-11-11 02:37:50 +00:00
|
|
|
// @see https://github.com/ossrs/srs/issues/425
|
2015-06-10 07:38:13 +00:00
|
|
|
delta = DEFAULT_FRAME_TIME_MS;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
last_pkt_correct_time = srs_max(0, last_pkt_correct_time + delta);
|
|
|
|
|
2014-12-07 03:25:05 +00:00
|
|
|
msg->timestamp = last_pkt_correct_time;
|
2014-03-18 03:32:58 +00:00
|
|
|
last_pkt_time = time;
|
|
|
|
|
2017-09-22 13:50:54 +00:00
|
|
|
return err;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
int64_t SrsRtmpJitter::get_time()
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
return last_pkt_correct_time;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-12-07 05:26:45 +00:00
|
|
|
#ifdef SRS_PERF_QUEUE_FAST_VECTOR
|
|
|
|
SrsFastVector::SrsFastVector()
|
|
|
|
{
|
|
|
|
count = 0;
|
2020-01-15 13:26:02 +00:00
|
|
|
nb_msgs = 8;
|
2014-12-07 05:26:45 +00:00
|
|
|
msgs = new SrsSharedPtrMessage*[nb_msgs];
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsFastVector::~SrsFastVector()
|
|
|
|
{
|
|
|
|
free();
|
2015-11-02 03:05:39 +00:00
|
|
|
srs_freepa(msgs);
|
2014-12-07 05:26:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsFastVector::size()
|
|
|
|
{
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
int SrsFastVector::begin()
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int SrsFastVector::end()
|
|
|
|
{
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsSharedPtrMessage** SrsFastVector::data()
|
|
|
|
{
|
|
|
|
return msgs;
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsSharedPtrMessage* SrsFastVector::at(int index)
|
|
|
|
{
|
|
|
|
srs_assert(index < count);
|
|
|
|
return msgs[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsFastVector::clear()
|
|
|
|
{
|
|
|
|
count = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsFastVector::erase(int _begin, int _end)
|
|
|
|
{
|
|
|
|
srs_assert(_begin < _end);
|
|
|
|
|
|
|
|
// move all erased to previous.
|
|
|
|
for (int i = 0; i < count - _end; i++) {
|
|
|
|
msgs[_begin + i] = msgs[_end + i];
|
|
|
|
}
|
|
|
|
|
|
|
|
// update the count.
|
|
|
|
count -= _end - _begin;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsFastVector::push_back(SrsSharedPtrMessage* msg)
|
|
|
|
{
|
|
|
|
// increase vector.
|
|
|
|
if (count >= nb_msgs) {
|
2020-01-15 13:26:02 +00:00
|
|
|
int size = srs_max(SRS_PERF_MW_MSGS * 8, nb_msgs * 2);
|
2014-12-07 05:26:45 +00:00
|
|
|
SrsSharedPtrMessage** buf = new SrsSharedPtrMessage*[size];
|
|
|
|
for (int i = 0; i < nb_msgs; i++) {
|
|
|
|
buf[i] = msgs[i];
|
|
|
|
}
|
2020-01-16 06:28:05 +00:00
|
|
|
srs_info("fast vector incrase %d=>%d", nb_msgs, size);
|
2014-12-07 05:26:45 +00:00
|
|
|
|
|
|
|
// use new array.
|
2015-11-02 03:05:39 +00:00
|
|
|
srs_freepa(msgs);
|
2014-12-07 05:26:45 +00:00
|
|
|
msgs = buf;
|
|
|
|
nb_msgs = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
msgs[count++] = msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsFastVector::free()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
SrsSharedPtrMessage* msg = msgs[i];
|
|
|
|
srs_freep(msg);
|
|
|
|
}
|
|
|
|
count = 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-01-19 04:56:05 +00:00
|
|
|
SrsMessageQueue::SrsMessageQueue(bool ignore_shrink)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2015-01-19 04:56:05 +00:00
|
|
|
_ignore_shrink = ignore_shrink;
|
2019-04-11 00:35:57 +00:00
|
|
|
max_queue_size = 0;
|
2014-03-18 03:32:58 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-12-05 10:47:17 +00:00
|
|
|
int SrsMessageQueue::size()
|
|
|
|
{
|
|
|
|
return (int)msgs.size();
|
|
|
|
}
|
|
|
|
|
2019-04-11 00:35:57 +00:00
|
|
|
srs_utime_t SrsMessageQueue::duration()
|
2014-12-05 10:47:17 +00:00
|
|
|
{
|
2019-04-11 00:35:57 +00:00
|
|
|
return (av_end_time - av_start_time);
|
2014-12-05 10:47:17 +00:00
|
|
|
}
|
|
|
|
|
2019-04-15 23:55:19 +00:00
|
|
|
void SrsMessageQueue::set_queue_size(srs_utime_t queue_size)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2019-04-15 23:55:19 +00:00
|
|
|
max_queue_size = queue_size;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2020-05-12 05:51:51 +00:00
|
|
|
srs_error_t SrsMessageQueue::enqueue(SrsSharedPtrMessage* msg, bool* is_overflow)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2020-04-18 12:37:08 +00:00
|
|
|
|
|
|
|
msgs.push_back(msg);
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-12-07 03:25:05 +00:00
|
|
|
if (msg->is_av()) {
|
2014-03-18 03:32:58 +00:00
|
|
|
if (av_start_time == -1) {
|
2019-04-11 00:35:57 +00:00
|
|
|
av_start_time = srs_utime_t(msg->timestamp * SRS_UTIME_MILLISECONDS);
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2019-04-12 02:00:39 +00:00
|
|
|
av_end_time = srs_utime_t(msg->timestamp * SRS_UTIME_MILLISECONDS);
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2020-05-12 05:51:51 +00:00
|
|
|
|
|
|
|
if (max_queue_size <= 0) {
|
|
|
|
return err;
|
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2019-04-11 00:35:57 +00:00
|
|
|
while (av_end_time - av_start_time > max_queue_size) {
|
2014-12-07 04:08:38 +00:00
|
|
|
// notice the caller queue already overflow and shrinked.
|
|
|
|
if (is_overflow) {
|
|
|
|
*is_overflow = true;
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
shrink();
|
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2020-05-12 05:51:51 +00:00
|
|
|
srs_error_t SrsMessageQueue::dump_packets(int max_count, SrsSharedPtrMessage** pmsgs, int& count)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-12-06 01:55:51 +00:00
|
|
|
|
2014-12-05 14:00:57 +00:00
|
|
|
int nb_msgs = (int)msgs.size();
|
|
|
|
if (nb_msgs <= 0) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2014-06-22 12:01:25 +00:00
|
|
|
srs_assert(max_count > 0);
|
2015-08-14 07:47:29 +00:00
|
|
|
count = srs_min(max_count, nb_msgs);
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2014-12-05 14:00:57 +00:00
|
|
|
SrsSharedPtrMessage** omsgs = msgs.data();
|
2020-04-18 12:37:08 +00:00
|
|
|
memcpy(pmsgs, omsgs, count * sizeof(SrsSharedPtrMessage*));
|
|
|
|
|
2020-05-12 05:51:51 +00:00
|
|
|
SrsSharedPtrMessage* last = omsgs[count - 1];
|
|
|
|
av_start_time = srs_utime_t(last->timestamp * SRS_UTIME_MILLISECONDS);
|
|
|
|
|
2015-08-14 07:51:02 +00:00
|
|
|
if (count >= nb_msgs) {
|
2014-07-27 03:57:08 +00:00
|
|
|
// the pmsgs is big enough and clear msgs at most time.
|
2014-03-18 03:32:58 +00:00
|
|
|
msgs.clear();
|
|
|
|
} else {
|
2014-07-27 03:57:08 +00:00
|
|
|
// erase some vector elements may cause memory copy,
|
|
|
|
// maybe can use more efficient vector.swap to avoid copy.
|
2014-12-05 03:24:05 +00:00
|
|
|
// @remark for the pmsgs is big enough, for instance, SRS_PERF_MW_MSGS 128,
|
2014-07-27 03:57:08 +00:00
|
|
|
// the rtmp play client will get 128msgs once, so this branch rarely execute.
|
2014-03-18 03:32:58 +00:00
|
|
|
msgs.erase(msgs.begin(), msgs.begin() + count);
|
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsMessageQueue::dump_packets(SrsConsumer* consumer, bool atc, SrsRtmpJitterAlgorithm ag)
|
2015-01-19 04:56:05 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2015-01-19 04:56:05 +00:00
|
|
|
|
|
|
|
int nb_msgs = (int)msgs.size();
|
|
|
|
if (nb_msgs <= 0) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2015-01-19 04:56:05 +00:00
|
|
|
}
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2015-01-19 04:56:05 +00:00
|
|
|
SrsSharedPtrMessage** omsgs = msgs.data();
|
|
|
|
for (int i = 0; i < nb_msgs; i++) {
|
|
|
|
SrsSharedPtrMessage* msg = omsgs[i];
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = consumer->enqueue(msg, atc, ag)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "consume message");
|
2015-01-19 04:56:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2015-01-19 04:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 10:25:55 +00:00
|
|
|
void SrsMessageQueue::shrink()
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2015-05-27 08:16:15 +00:00
|
|
|
SrsSharedPtrMessage* video_sh = NULL;
|
|
|
|
SrsSharedPtrMessage* audio_sh = NULL;
|
|
|
|
int msgs_size = (int)msgs.size();
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2015-05-27 08:16:15 +00:00
|
|
|
// remove all msg
|
|
|
|
// igone the sequence header
|
|
|
|
for (int i = 0; i < (int)msgs.size(); i++) {
|
2014-12-07 05:26:45 +00:00
|
|
|
SrsSharedPtrMessage* msg = msgs.at(i);
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2017-02-12 12:38:39 +00:00
|
|
|
if (msg->is_video() && SrsFlvVideo::sh(msg->payload, msg->size)) {
|
2015-05-27 08:16:15 +00:00
|
|
|
srs_freep(video_sh);
|
|
|
|
video_sh = msg;
|
|
|
|
continue;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2017-02-12 12:38:39 +00:00
|
|
|
else if (msg->is_audio() && SrsFlvAudio::sh(msg->payload, msg->size)) {
|
2015-05-27 08:16:15 +00:00
|
|
|
srs_freep(audio_sh);
|
|
|
|
audio_sh = msg;
|
|
|
|
continue;
|
|
|
|
}
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2015-05-27 08:16:15 +00:00
|
|
|
srs_freep(msg);
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2017-03-25 09:21:39 +00:00
|
|
|
msgs.clear();
|
|
|
|
|
2015-05-27 08:16:15 +00:00
|
|
|
// update av_start_time
|
|
|
|
av_start_time = av_end_time;
|
|
|
|
//push_back secquence header and update timestamp
|
|
|
|
if (video_sh) {
|
2019-04-12 02:00:39 +00:00
|
|
|
video_sh->timestamp = srsu2ms(av_end_time);
|
2015-05-27 08:16:15 +00:00
|
|
|
msgs.push_back(video_sh);
|
|
|
|
}
|
|
|
|
if (audio_sh) {
|
2019-04-12 02:00:39 +00:00
|
|
|
audio_sh->timestamp = srsu2ms(av_end_time);
|
2015-05-27 08:16:15 +00:00
|
|
|
msgs.push_back(audio_sh);
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2018-01-01 11:39:57 +00:00
|
|
|
if (!_ignore_shrink) {
|
2019-04-11 00:35:57 +00:00
|
|
|
srs_trace("shrinking, size=%d, removed=%d, max=%dms", (int)msgs.size(), msgs_size - (int)msgs.size(), srsu2msi(max_queue_size));
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
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-12-07 05:26:45 +00:00
|
|
|
#ifndef SRS_PERF_QUEUE_FAST_VECTOR
|
2014-04-29 06:44:07 +00:00
|
|
|
std::vector<SrsSharedPtrMessage*>::iterator it;
|
2017-03-25 09:21:39 +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);
|
|
|
|
}
|
2014-12-07 05:26:45 +00:00
|
|
|
#else
|
|
|
|
msgs.free();
|
|
|
|
#endif
|
2017-03-25 09:21:39 +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
|
|
|
}
|
|
|
|
|
2015-06-09 06:38:05 +00:00
|
|
|
ISrsWakable::ISrsWakable()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ISrsWakable::~ISrsWakable()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-09-11 09:03:48 +00:00
|
|
|
SrsConsumer::SrsConsumer(SrsSource* s)
|
2013-12-15 10:25:55 +00:00
|
|
|
{
|
2015-12-26 04:13:17 +00:00
|
|
|
source = s;
|
2014-03-18 03:32:58 +00:00
|
|
|
paused = false;
|
|
|
|
jitter = new SrsRtmpJitter();
|
|
|
|
queue = new SrsMessageQueue();
|
2014-05-27 11:18:31 +00:00
|
|
|
should_update_source_id = false;
|
2014-12-06 01:55:51 +00:00
|
|
|
|
|
|
|
#ifdef SRS_PERF_QUEUE_COND_WAIT
|
2017-05-30 01:05:02 +00:00
|
|
|
mw_wait = srs_cond_new();
|
2014-12-06 01:55:51 +00:00
|
|
|
mw_min_msgs = 0;
|
|
|
|
mw_duration = 0;
|
|
|
|
mw_waiting = false;
|
|
|
|
#endif
|
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);
|
2014-12-06 01:55:51 +00:00
|
|
|
|
|
|
|
#ifdef SRS_PERF_QUEUE_COND_WAIT
|
2017-05-30 01:05:02 +00:00
|
|
|
srs_cond_destroy(mw_wait);
|
2014-12-06 01:55:51 +00:00
|
|
|
#endif
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
2019-04-15 23:55:19 +00:00
|
|
|
void SrsConsumer::set_queue_size(srs_utime_t queue_size)
|
2013-12-15 10:25:55 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
queue->set_queue_size(queue_size);
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
2014-05-27 11:18:31 +00:00
|
|
|
void SrsConsumer::update_source_id()
|
|
|
|
{
|
|
|
|
should_update_source_id = true;
|
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
int64_t SrsConsumer::get_time()
|
2013-12-15 10:25:55 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return jitter->get_time();
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsConsumer::enqueue(SrsSharedPtrMessage* shared_msg, bool atc, SrsRtmpJitterAlgorithm ag)
|
2013-12-15 10:25:55 +00:00
|
|
|
{
|
2017-09-22 13:50:54 +00:00
|
|
|
srs_error_t err = srs_success;
|
2020-08-06 04:02:32 +00:00
|
|
|
|
2015-03-21 03:55:28 +00:00
|
|
|
SrsSharedPtrMessage* msg = shared_msg->copy();
|
2020-04-18 12:37:08 +00:00
|
|
|
|
2020-05-12 05:51:51 +00:00
|
|
|
if (!atc) {
|
2017-09-22 13:50:54 +00:00
|
|
|
if ((err = jitter->correct(msg, ag)) != srs_success) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return srs_error_wrap(err, "consume message");
|
2014-03-26 08:25:02 +00:00
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2020-04-18 12:37:08 +00:00
|
|
|
|
2020-05-12 05:51:51 +00:00
|
|
|
if ((err = queue->enqueue(msg, NULL)) != srs_success) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return srs_error_wrap(err, "enqueue message");
|
2014-12-05 10:47:17 +00:00
|
|
|
}
|
|
|
|
|
2014-12-07 04:08:38 +00:00
|
|
|
#ifdef SRS_PERF_QUEUE_COND_WAIT
|
2014-12-06 01:55:51 +00:00
|
|
|
// fire the mw when msgs is enough.
|
|
|
|
if (mw_waiting) {
|
2020-04-18 12:37:08 +00:00
|
|
|
// For RTMP, we wait for messages and duration.
|
2019-04-11 00:35:57 +00:00
|
|
|
srs_utime_t duration = queue->duration();
|
2014-12-06 01:55:51 +00:00
|
|
|
bool match_min_msgs = queue->size() > mw_min_msgs;
|
|
|
|
|
2017-01-18 03:48:31 +00:00
|
|
|
// For ATC, maybe the SH timestamp bigger than A/V packet,
|
|
|
|
// when encoder republish or overflow.
|
|
|
|
// @see https://github.com/ossrs/srs/pull/749
|
2019-04-11 00:35:57 +00:00
|
|
|
if (atc && duration < 0) {
|
2017-05-30 01:05:02 +00:00
|
|
|
srs_cond_signal(mw_wait);
|
2017-01-18 03:48:31 +00:00
|
|
|
mw_waiting = false;
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2017-01-18 03:48:31 +00:00
|
|
|
}
|
|
|
|
|
2014-12-06 01:55:51 +00:00
|
|
|
// when duration ok, signal to flush.
|
2019-04-11 00:35:57 +00:00
|
|
|
if (match_min_msgs && duration > mw_duration) {
|
2017-05-30 01:05:02 +00:00
|
|
|
srs_cond_signal(mw_wait);
|
2014-12-06 01:55:51 +00:00
|
|
|
mw_waiting = false;
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2014-12-06 01:55:51 +00:00
|
|
|
}
|
|
|
|
}
|
2014-12-07 04:08:38 +00:00
|
|
|
#endif
|
2014-12-06 01:55:51 +00:00
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsConsumer::dump_packets(SrsMessageArray* msgs, int& count)
|
2013-12-15 10:25:55 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-12-05 08:44:11 +00:00
|
|
|
|
2015-08-14 07:47:29 +00:00
|
|
|
srs_assert(count >= 0);
|
2014-12-05 08:44:11 +00:00
|
|
|
srs_assert(msgs->max > 0);
|
2014-06-22 12:01:25 +00:00
|
|
|
|
2015-08-14 07:47:29 +00:00
|
|
|
// the count used as input to reset the max if positive.
|
|
|
|
int max = count? srs_min(count, msgs->max) : msgs->max;
|
|
|
|
|
|
|
|
// the count specifies the max acceptable count,
|
|
|
|
// here maybe 1+, and we must set to 0 when got nothing.
|
|
|
|
count = 0;
|
|
|
|
|
2014-05-27 11:18:31 +00:00
|
|
|
if (should_update_source_id) {
|
2020-10-31 11:25:56 +00:00
|
|
|
srs_trace("update source_id=%s/%s", source->source_id().c_str(), source->pre_source_id().c_str());
|
2014-05-27 11:18:31 +00:00
|
|
|
should_update_source_id = false;
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// paused, return nothing.
|
|
|
|
if (paused) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2014-12-05 08:44:11 +00:00
|
|
|
}
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2014-12-05 10:47:17 +00:00
|
|
|
// pump msgs from queue.
|
2020-05-12 05:51:51 +00:00
|
|
|
if ((err = queue->dump_packets(max, msgs->msgs, count)) != srs_success) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return srs_error_wrap(err, "dump packets");
|
2014-12-05 10:47:17 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2014-12-05 06:38:43 +00:00
|
|
|
}
|
|
|
|
|
2014-12-06 01:55:51 +00:00
|
|
|
#ifdef SRS_PERF_QUEUE_COND_WAIT
|
2019-04-11 00:35:57 +00:00
|
|
|
void SrsConsumer::wait(int nb_msgs, srs_utime_t msgs_duration)
|
2014-12-06 01:55:51 +00:00
|
|
|
{
|
2015-01-23 09:07:17 +00:00
|
|
|
if (paused) {
|
2019-04-11 00:43:42 +00:00
|
|
|
srs_usleep(SRS_CONSTS_RTMP_PULSE);
|
2015-01-23 09:07:17 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2014-12-06 01:55:51 +00:00
|
|
|
mw_min_msgs = nb_msgs;
|
2019-04-11 00:35:57 +00:00
|
|
|
mw_duration = msgs_duration;
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2019-04-11 00:35:57 +00:00
|
|
|
srs_utime_t duration = queue->duration();
|
2014-12-06 01:55:51 +00:00
|
|
|
bool match_min_msgs = queue->size() > mw_min_msgs;
|
|
|
|
|
|
|
|
// when duration ok, signal to flush.
|
2019-04-11 00:35:57 +00:00
|
|
|
if (match_min_msgs && duration > mw_duration) {
|
2014-12-06 01:55:51 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// the enqueue will notify this cond.
|
|
|
|
mw_waiting = true;
|
2014-12-12 13:51:06 +00:00
|
|
|
|
2014-12-16 01:26:22 +00:00
|
|
|
// use cond block wait for high performance mode.
|
2017-05-30 01:05:02 +00:00
|
|
|
srs_cond_wait(mw_wait);
|
2014-12-06 01:55:51 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsConsumer::on_play_client_pause(bool is_pause)
|
2013-12-15 10:25:55 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
srs_trace("stream consumer change pause state %d=>%d", paused, is_pause);
|
|
|
|
paused = is_pause;
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2015-06-09 06:38:05 +00:00
|
|
|
void SrsConsumer::wakeup()
|
|
|
|
{
|
|
|
|
#ifdef SRS_PERF_QUEUE_COND_WAIT
|
|
|
|
if (mw_waiting) {
|
2017-05-30 01:05:02 +00:00
|
|
|
srs_cond_signal(mw_wait);
|
2015-06-09 06:38:05 +00:00
|
|
|
mw_waiting = false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
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;
|
2014-10-08 06:28:09 +00:00
|
|
|
audio_after_last_video_count = 0;
|
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
|
|
|
}
|
|
|
|
|
2015-06-07 01:27:47 +00:00
|
|
|
void SrsGopCache::dispose()
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
2015-08-29 23:26:55 +00:00
|
|
|
void SrsGopCache::set(bool v)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2015-08-29 23:26:55 +00:00
|
|
|
enable_gop_cache = v;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2015-08-29 23:26:55 +00:00
|
|
|
if (!v) {
|
2014-03-18 03:32:58 +00:00
|
|
|
clear();
|
|
|
|
return;
|
|
|
|
}
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2015-08-29 23:26:55 +00:00
|
|
|
bool SrsGopCache::enabled()
|
|
|
|
{
|
|
|
|
return enable_gop_cache;
|
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsGopCache::cache(SrsSharedPtrMessage* shared_msg)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
if (!enable_gop_cache) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2014-12-05 15:49:53 +00:00
|
|
|
// the gop cache know when to gop it.
|
2015-03-21 03:55:28 +00:00
|
|
|
SrsSharedPtrMessage* msg = shared_msg;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
// got video, update the video count if acceptable
|
2014-12-07 03:25:05 +00:00
|
|
|
if (msg->is_video()) {
|
2015-06-06 12:23:18 +00:00
|
|
|
// drop video when not h.264
|
2017-02-12 12:38:39 +00:00
|
|
|
if (!SrsFlvVideo::h264(msg->payload, msg->size)) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2015-06-06 12:23:18 +00:00
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
cached_video_count++;
|
2014-10-08 06:28:09 +00:00
|
|
|
audio_after_last_video_count = 0;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// no acceptable video or pure audio, disable the cache.
|
2014-10-08 07:15:57 +00:00
|
|
|
if (pure_audio()) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2014-07-26 04:22:39 +00:00
|
|
|
// ok, gop cache enabled, and got an audio.
|
2014-12-07 03:25:05 +00:00
|
|
|
if (msg->is_audio()) {
|
2014-10-08 06:28:09 +00:00
|
|
|
audio_after_last_video_count++;
|
2014-07-26 04:22:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// clear gop cache when pure audio count overflow
|
2015-03-21 03:55:28 +00:00
|
|
|
if (audio_after_last_video_count > SRS_PURE_AUDIO_GUESS_COUNT) {
|
2014-07-26 04:22:39 +00:00
|
|
|
srs_warn("clear gop cache for guess pure audio overflow");
|
|
|
|
clear();
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2014-07-26 04:22:39 +00:00
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// clear gop cache when got key frame
|
2017-02-12 12:38:39 +00:00
|
|
|
if (msg->is_video() && SrsFlvVideo::keyframe(msg->payload, msg->size)) {
|
2014-03-18 03:32:58 +00:00
|
|
|
clear();
|
|
|
|
|
|
|
|
// curent msg is video frame, so we set to 1.
|
|
|
|
cached_video_count = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// cache the frame.
|
|
|
|
gop_cache.push_back(msg->copy());
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
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();
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
cached_video_count = 0;
|
2014-10-08 06:28:09 +00:00
|
|
|
audio_after_last_video_count = 0;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsGopCache::dump(SrsConsumer* consumer, bool atc, SrsRtmpJitterAlgorithm jitter_algorithm)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
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;
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = consumer->enqueue(msg, atc, jitter_algorithm)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "enqueue message");
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
srs_trace("dispatch cached gop success. count=%d, duration=%d", (int)gop_cache.size(), consumer->get_time());
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-03-26 08:25:02 +00:00
|
|
|
bool SrsGopCache::empty()
|
|
|
|
{
|
|
|
|
return gop_cache.empty();
|
|
|
|
}
|
|
|
|
|
2019-04-19 00:04:09 +00:00
|
|
|
srs_utime_t SrsGopCache::start_time()
|
2014-03-26 08:25:02 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2019-04-19 00:04:09 +00:00
|
|
|
return srs_utime_t(msg->timestamp * SRS_UTIME_MILLISECONDS);
|
2014-03-26 08:25:02 +00:00
|
|
|
}
|
|
|
|
|
2014-10-08 07:15:57 +00:00
|
|
|
bool SrsGopCache::pure_audio()
|
|
|
|
{
|
|
|
|
return cached_video_count == 0;
|
|
|
|
}
|
|
|
|
|
2015-01-18 10:39:53 +00:00
|
|
|
ISrsSourceHandler::ISrsSourceHandler()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ISrsSourceHandler::~ISrsSourceHandler()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// TODO: FIXME: Remove it?
|
|
|
|
bool srs_hls_can_continue(int ret, SrsSharedPtrMessage* sh, SrsSharedPtrMessage* msg)
|
2015-04-15 09:12:22 +00:00
|
|
|
{
|
2017-01-19 04:38:55 +00:00
|
|
|
// only continue for decode error.
|
|
|
|
if (ret != ERROR_HLS_DECODE_ERROR) {
|
|
|
|
return false;
|
2015-04-15 09:12:22 +00:00
|
|
|
}
|
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// when video size equals to sequence header,
|
|
|
|
// the video actually maybe a sequence header,
|
|
|
|
// continue to make ffmpeg happy.
|
|
|
|
if (sh && sh->size == msg->size) {
|
|
|
|
srs_warn("the msg is actually a sequence header, ignore this packet.");
|
|
|
|
return true;
|
2015-04-15 09:12:22 +00:00
|
|
|
}
|
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
return false;
|
2015-04-15 09:12:22 +00:00
|
|
|
}
|
|
|
|
|
2017-01-22 09:07:55 +00:00
|
|
|
SrsMixQueue::SrsMixQueue()
|
|
|
|
{
|
|
|
|
nb_videos = 0;
|
|
|
|
nb_audios = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsMixQueue::~SrsMixQueue()
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsMixQueue::clear()
|
|
|
|
{
|
|
|
|
std::multimap<int64_t, SrsSharedPtrMessage*>::iterator it;
|
|
|
|
for (it = msgs.begin(); it != msgs.end(); ++it) {
|
|
|
|
SrsSharedPtrMessage* msg = it->second;
|
|
|
|
srs_freep(msg);
|
|
|
|
}
|
|
|
|
msgs.clear();
|
|
|
|
|
|
|
|
nb_videos = 0;
|
|
|
|
nb_audios = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsMixQueue::push(SrsSharedPtrMessage* msg)
|
|
|
|
{
|
|
|
|
msgs.insert(std::make_pair(msg->timestamp, msg));
|
|
|
|
|
|
|
|
if (msg->is_video()) {
|
|
|
|
nb_videos++;
|
|
|
|
} else {
|
|
|
|
nb_audios++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsSharedPtrMessage* SrsMixQueue::pop()
|
|
|
|
{
|
|
|
|
bool mix_ok = false;
|
|
|
|
|
|
|
|
// pure video
|
|
|
|
if (nb_videos >= SRS_MIX_CORRECT_PURE_AV && nb_audios == 0) {
|
|
|
|
mix_ok = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// pure audio
|
|
|
|
if (nb_audios >= SRS_MIX_CORRECT_PURE_AV && nb_videos == 0) {
|
|
|
|
mix_ok = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// got 1 video and 1 audio, mix ok.
|
|
|
|
if (nb_videos >= 1 && nb_audios >= 1) {
|
|
|
|
mix_ok = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mix_ok) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// pop the first msg.
|
|
|
|
std::multimap<int64_t, SrsSharedPtrMessage*>::iterator it = msgs.begin();
|
|
|
|
SrsSharedPtrMessage* msg = it->second;
|
|
|
|
msgs.erase(it);
|
|
|
|
|
|
|
|
if (msg->is_video()) {
|
|
|
|
nb_videos--;
|
|
|
|
} else {
|
|
|
|
nb_audios--;
|
|
|
|
}
|
|
|
|
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
2017-02-11 13:14:28 +00:00
|
|
|
SrsOriginHub::SrsOriginHub()
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2017-02-11 13:14:28 +00:00
|
|
|
source = NULL;
|
2015-09-15 07:58:57 +00:00
|
|
|
req = NULL;
|
2017-02-09 06:33:56 +00:00
|
|
|
is_active = false;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2015-02-27 12:39:36 +00:00
|
|
|
hls = new SrsHls();
|
2017-02-19 14:03:51 +00:00
|
|
|
dash = new SrsDash();
|
2015-02-27 12:39:36 +00:00
|
|
|
dvr = new SrsDvr();
|
2014-03-18 03:32:58 +00:00
|
|
|
encoder = new SrsEncoder();
|
2020-04-29 12:02:28 +00:00
|
|
|
#ifdef SRS_HDS
|
2017-02-11 13:14:28 +00:00
|
|
|
hds = new SrsHds();
|
2015-03-12 03:15:15 +00:00
|
|
|
#endif
|
2015-08-25 14:29:00 +00:00
|
|
|
ng_exec = new SrsNgExec();
|
2017-02-12 10:18:18 +00:00
|
|
|
format = new SrsRtmpFormat();
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
_srs_config->subscribe(this);
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
SrsOriginHub::~SrsOriginHub()
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
_srs_config->unsubscribe(this);
|
|
|
|
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
|
|
|
srs_freep(forwarder);
|
|
|
|
}
|
|
|
|
forwarders.clear();
|
|
|
|
}
|
2015-08-25 14:29:00 +00:00
|
|
|
srs_freep(ng_exec);
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2017-02-11 15:09:23 +00:00
|
|
|
srs_freep(format);
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(hls);
|
2017-02-11 13:14:28 +00:00
|
|
|
srs_freep(dash);
|
2014-04-16 01:28:02 +00:00
|
|
|
srs_freep(dvr);
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(encoder);
|
2020-04-29 12:02:28 +00:00
|
|
|
#ifdef SRS_HDS
|
2015-03-12 03:15:15 +00:00
|
|
|
srs_freep(hds);
|
|
|
|
#endif
|
2015-05-30 02:48:02 +00:00
|
|
|
}
|
|
|
|
|
2017-06-11 01:40:07 +00:00
|
|
|
srs_error_t SrsOriginHub::initialize(SrsSource* s, SrsRequest* r)
|
2015-05-30 02:48:02 +00:00
|
|
|
{
|
2017-06-11 01:40:07 +00:00
|
|
|
srs_error_t err = srs_success;
|
2015-05-30 02:48:02 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
req = r;
|
2017-02-11 13:14:28 +00:00
|
|
|
source = s;
|
2017-01-19 04:38:55 +00:00
|
|
|
|
2017-06-11 01:40:07 +00:00
|
|
|
if ((err = format->initialize()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "format initialize");
|
2017-02-11 15:09:23 +00:00
|
|
|
}
|
2020-03-08 11:20:46 +00:00
|
|
|
|
2017-06-11 01:40:07 +00:00
|
|
|
if ((err = hls->initialize(this, req)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "hls initialize");
|
2015-05-30 02:48:02 +00:00
|
|
|
}
|
|
|
|
|
2017-06-11 01:40:07 +00:00
|
|
|
if ((err = dash->initialize(this, req)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "dash initialize");
|
2017-02-11 13:14:28 +00:00
|
|
|
}
|
|
|
|
|
2017-06-11 01:40:07 +00:00
|
|
|
if ((err = dvr->initialize(this, req)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "dvr initialize");
|
2016-09-05 06:56:31 +00:00
|
|
|
}
|
|
|
|
|
2017-06-11 01:40:07 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsOriginHub::dispose()
|
|
|
|
{
|
|
|
|
hls->dispose();
|
2017-02-11 13:14:28 +00:00
|
|
|
|
|
|
|
// TODO: Support dispose DASH.
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-06-11 01:40:07 +00:00
|
|
|
srs_error_t SrsOriginHub::cycle()
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
2017-06-11 01:40:07 +00:00
|
|
|
srs_error_t err = srs_success;
|
2016-09-05 06:13:37 +00:00
|
|
|
|
2017-06-11 01:40:07 +00:00
|
|
|
if ((err = hls->cycle()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "hls cycle");
|
2016-09-05 06:13:37 +00:00
|
|
|
}
|
|
|
|
|
2017-02-11 13:14:28 +00:00
|
|
|
// TODO: Support cycle DASH.
|
|
|
|
|
2017-06-11 01:40:07 +00:00
|
|
|
return err;
|
2016-09-05 06:13:37 +00:00
|
|
|
}
|
|
|
|
|
2020-01-27 11:46:08 +00:00
|
|
|
bool SrsOriginHub::active()
|
|
|
|
{
|
|
|
|
return is_active;
|
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsOriginHub::on_meta_data(SrsSharedPtrMessage* shared_metadata, SrsOnMetaDataPacket* packet)
|
2014-06-25 09:14:11 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-06-25 09:14:11 +00:00
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = format->on_metadata(packet)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "Format parse metadata");
|
2017-02-11 15:09:23 +00:00
|
|
|
}
|
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// copy to all forwarders
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = forwarder->on_meta_data(shared_metadata)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "Forwarder consume metadata");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-25 09:14:11 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = dvr->on_meta_data(shared_metadata)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "DVR consume metadata");
|
2017-02-06 12:58:52 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsOriginHub::on_audio(SrsSharedPtrMessage* shared_audio)
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
2017-09-22 13:50:54 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-06-25 09:14:11 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
SrsSharedPtrMessage* msg = shared_audio;
|
2020-04-30 02:57:03 +00:00
|
|
|
|
|
|
|
// TODO: FIXME: Support parsing OPUS for RTC.
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = format->on_audio(msg)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "format consume audio");
|
2017-02-11 15:09:23 +00:00
|
|
|
}
|
|
|
|
|
2017-02-12 10:18:18 +00:00
|
|
|
// cache the sequence header if aac
|
|
|
|
// donot cache the sequence header to gop_cache, return here.
|
|
|
|
if (format->is_aac_sequence_header()) {
|
|
|
|
srs_assert(format->acodec);
|
2017-02-12 12:38:39 +00:00
|
|
|
SrsAudioCodecConfig* c = format->acodec;
|
2017-02-12 10:18:18 +00:00
|
|
|
|
|
|
|
static int flv_sample_sizes[] = {8, 16, 0};
|
|
|
|
static int flv_sound_types[] = {1, 2, 0};
|
|
|
|
|
|
|
|
// when got audio stream info.
|
|
|
|
SrsStatistic* stat = SrsStatistic::instance();
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = stat->on_audio_info(req, SrsAudioCodecIdAAC, c->sound_rate, c->sound_type, c->aac_object)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "stat audio");
|
2017-02-12 10:18:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
srs_trace("%dB audio sh, codec(%d, profile=%s, %dchannels, %dkbps, %dHZ), flv(%dbits, %dchannels, %dHZ)",
|
2017-03-25 09:21:39 +00:00
|
|
|
msg->size, c->id, srs_aac_object2str(c->aac_object).c_str(), c->aac_channels,
|
|
|
|
c->audio_data_rate / 1000, srs_aac_srates[c->aac_sample_rate],
|
|
|
|
flv_sample_sizes[c->sound_size], flv_sound_types[c->sound_type],
|
|
|
|
srs_flv_srates[c->sound_rate]);
|
2017-02-12 10:18:18 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 13:50:54 +00:00
|
|
|
if ((err = hls->on_audio(msg, format)) != srs_success) {
|
2017-01-19 04:38:55 +00:00
|
|
|
// apply the error strategy for hls.
|
|
|
|
// @see https://github.com/ossrs/srs/issues/264
|
|
|
|
std::string hls_error_strategy = _srs_config->get_hls_on_error(req->vhost);
|
|
|
|
if (srs_config_hls_is_on_error_ignore(hls_error_strategy)) {
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_warn("hls: ignore audio error %s", srs_error_desc(err).c_str());
|
2017-01-19 04:38:55 +00:00
|
|
|
hls->on_unpublish();
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_reset(err);
|
2017-01-19 04:38:55 +00:00
|
|
|
} else if (srs_config_hls_is_on_error_continue(hls_error_strategy)) {
|
2017-09-23 14:12:33 +00:00
|
|
|
if (srs_hls_can_continue(srs_error_code(err), source->meta->ash(), msg)) {
|
|
|
|
srs_error_reset(err);
|
2017-01-19 04:38:55 +00:00
|
|
|
} else {
|
2017-09-23 14:12:33 +00:00
|
|
|
return srs_error_wrap(err, "hls: audio");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
} else {
|
2017-09-23 14:12:33 +00:00
|
|
|
return srs_error_wrap(err, "hls: audio");
|
2015-08-29 15:36:03 +00:00
|
|
|
}
|
|
|
|
}
|
2015-04-15 09:12:22 +00:00
|
|
|
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = dash->on_audio(msg, format)) != srs_success) {
|
|
|
|
srs_warn("dash: ignore audio error %s", srs_error_desc(err).c_str());
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_reset(err);
|
2018-01-01 11:39:57 +00:00
|
|
|
dash->on_unpublish();
|
2017-02-11 13:14:28 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = dvr->on_audio(msg, format)) != srs_success) {
|
|
|
|
srs_warn("dvr: ignore audio error %s", srs_error_desc(err).c_str());
|
|
|
|
srs_error_reset(err);
|
2018-01-01 11:39:57 +00:00
|
|
|
dvr->on_unpublish();
|
2015-04-15 09:12:22 +00:00
|
|
|
}
|
|
|
|
|
2020-04-29 12:02:28 +00:00
|
|
|
#ifdef SRS_HDS
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = hds->on_audio(msg)) != srs_success) {
|
|
|
|
srs_warn("hds: ignore audio error %s", srs_error_desc(err).c_str());
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_reset(err);
|
2018-01-01 11:39:57 +00:00
|
|
|
hds->on_unpublish();
|
2015-08-29 23:26:55 +00:00
|
|
|
}
|
2017-01-19 04:38:55 +00:00
|
|
|
#endif
|
2015-08-29 23:26:55 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// copy to all forwarders.
|
2015-08-29 23:26:55 +00:00
|
|
|
if (true) {
|
2017-01-19 04:38:55 +00:00
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = forwarder->on_audio(msg)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "forward: audio");
|
2015-08-29 23:26:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2015-04-15 09:12:22 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_sequence_header)
|
2013-12-15 04:34:22 +00:00
|
|
|
{
|
2017-09-22 13:50:54 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
SrsSharedPtrMessage* msg = shared_video;
|
|
|
|
|
2017-02-12 10:18:18 +00:00
|
|
|
// user can disable the sps parse to workaround when parse sps failed.
|
|
|
|
// @see https://github.com/ossrs/srs/issues/474
|
|
|
|
if (is_sequence_header) {
|
|
|
|
format->avc_parse_sps = _srs_config->get_parse_sps(req->vhost);
|
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = format->on_video(msg)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "format consume video");
|
2017-02-11 15:09:23 +00:00
|
|
|
}
|
|
|
|
|
2017-02-12 10:18:18 +00:00
|
|
|
// cache the sequence header if h264
|
|
|
|
// donot cache the sequence header to gop_cache, return here.
|
|
|
|
if (format->is_avc_sequence_header()) {
|
2017-02-12 12:38:39 +00:00
|
|
|
SrsVideoCodecConfig* c = format->vcodec;
|
2017-02-12 10:18:18 +00:00
|
|
|
srs_assert(c);
|
|
|
|
|
|
|
|
// when got video stream info.
|
|
|
|
SrsStatistic* stat = SrsStatistic::instance();
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = stat->on_video_info(req, SrsVideoCodecIdAVC, c->avc_profile, c->avc_level, c->width, c->height)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "stat video");
|
2017-02-12 10:18:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
srs_trace("%dB video sh, codec(%d, profile=%s, level=%s, %dx%d, %dkbps, %.1ffps, %.1fs)",
|
2017-03-25 09:21:39 +00:00
|
|
|
msg->size, c->id, srs_avc_profile2str(c->avc_profile).c_str(),
|
|
|
|
srs_avc_level2str(c->avc_level).c_str(), c->width, c->height,
|
|
|
|
c->video_data_rate / 1000, c->frame_rate, c->duration);
|
2017-02-12 10:18:18 +00:00
|
|
|
}
|
2020-01-25 10:05:18 +00:00
|
|
|
|
|
|
|
// Ignore video data when no sps/pps
|
|
|
|
// @bug https://github.com/ossrs/srs/issues/703#issuecomment-578393155
|
|
|
|
if (format->vcodec && !format->vcodec->is_avc_codec_ok()) {
|
|
|
|
return err;
|
|
|
|
}
|
2017-02-12 10:18:18 +00:00
|
|
|
|
2017-09-22 13:50:54 +00:00
|
|
|
if ((err = hls->on_video(msg, format)) != srs_success) {
|
2020-03-16 09:39:06 +00:00
|
|
|
// TODO: We should support more strategies.
|
2017-01-19 04:38:55 +00:00
|
|
|
// apply the error strategy for hls.
|
|
|
|
// @see https://github.com/ossrs/srs/issues/264
|
|
|
|
std::string hls_error_strategy = _srs_config->get_hls_on_error(req->vhost);
|
|
|
|
if (srs_config_hls_is_on_error_ignore(hls_error_strategy)) {
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_warn("hls: ignore video error %s", srs_error_desc(err).c_str());
|
2017-01-19 04:38:55 +00:00
|
|
|
hls->on_unpublish();
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_reset(err);
|
2017-01-19 04:38:55 +00:00
|
|
|
} else if (srs_config_hls_is_on_error_continue(hls_error_strategy)) {
|
2018-01-01 11:39:57 +00:00
|
|
|
if (srs_hls_can_continue(srs_error_code(err), source->meta->vsh(), msg)) {
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_reset(err);
|
2017-01-19 04:38:55 +00:00
|
|
|
} else {
|
2017-09-23 14:12:33 +00:00
|
|
|
return srs_error_wrap(err, "hls: video");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
} else {
|
2017-09-23 14:12:33 +00:00
|
|
|
return srs_error_wrap(err, "hls: video");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2015-08-25 14:59:17 +00:00
|
|
|
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = dash->on_video(msg, format)) != srs_success) {
|
|
|
|
srs_warn("dash: ignore video error %s", srs_error_desc(err).c_str());
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_reset(err);
|
2018-01-01 11:39:57 +00:00
|
|
|
dash->on_unpublish();
|
2017-02-11 13:14:28 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = dvr->on_video(msg, format)) != srs_success) {
|
|
|
|
srs_warn("dvr: ignore video error %s", srs_error_desc(err).c_str());
|
|
|
|
srs_error_reset(err);
|
2018-01-01 11:39:57 +00:00
|
|
|
dvr->on_unpublish();
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2020-04-29 12:02:28 +00:00
|
|
|
#ifdef SRS_HDS
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = hds->on_video(msg)) != srs_success) {
|
|
|
|
srs_warn("hds: ignore video error %s", srs_error_desc(err).c_str());
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_reset(err);
|
2018-01-01 11:39:57 +00:00
|
|
|
hds->on_unpublish();
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// copy to all forwarders.
|
|
|
|
if (!forwarders.empty()) {
|
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = forwarder->on_video(msg)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "forward video");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2013-12-15 04:34:22 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsOriginHub::on_publish()
|
2013-12-15 05:07:39 +00:00
|
|
|
{
|
2017-09-22 13:50:54 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// create forwarders
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = create_forwarders()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "create forwarders");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: FIXME: use initialize to set req.
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = encoder->on_publish(req)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "encoder publish");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
2020-03-22 10:17:05 +00:00
|
|
|
|
2017-09-22 13:50:54 +00:00
|
|
|
if ((err = hls->on_publish()) != srs_success) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return srs_error_wrap(err, "hls publish");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = dash->on_publish()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "dash publish");
|
2017-02-11 13:14:28 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = dvr->on_publish()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "dvr publish");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: FIXME: use initialize to set req.
|
2020-04-29 12:02:28 +00:00
|
|
|
#ifdef SRS_HDS
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = hds->on_publish(req)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "hds publish");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// TODO: FIXME: use initialize to set req.
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = ng_exec->on_publish(req)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "exec publish");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-02-09 06:33:56 +00:00
|
|
|
is_active = true;
|
2014-06-25 09:14:11 +00:00
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsOriginHub::on_unpublish()
|
|
|
|
{
|
2017-02-09 06:33:56 +00:00
|
|
|
is_active = false;
|
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// destroy all forwarders
|
|
|
|
destroy_forwarders();
|
|
|
|
|
|
|
|
encoder->on_unpublish();
|
|
|
|
hls->on_unpublish();
|
2017-02-11 13:14:28 +00:00
|
|
|
dash->on_unpublish();
|
2017-01-19 04:38:55 +00:00
|
|
|
dvr->on_unpublish();
|
|
|
|
|
2020-04-29 12:02:28 +00:00
|
|
|
#ifdef SRS_HDS
|
2017-01-19 04:38:55 +00:00
|
|
|
hds->on_unpublish();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
ng_exec->on_unpublish();
|
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsOriginHub::on_forwarder_start(SrsForwarder* forwarder)
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2017-01-19 04:38:55 +00:00
|
|
|
|
|
|
|
SrsSharedPtrMessage* cache_metadata = source->meta->data();
|
|
|
|
SrsSharedPtrMessage* cache_sh_video = source->meta->vsh();
|
|
|
|
SrsSharedPtrMessage* cache_sh_audio = source->meta->ash();
|
|
|
|
|
|
|
|
// feed the forwarder the metadata/sequence header,
|
|
|
|
// when reload to enable the forwarder.
|
2017-09-23 14:12:33 +00:00
|
|
|
if (cache_metadata && (err = forwarder->on_meta_data(cache_metadata)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "forward metadata");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
2017-09-23 14:12:33 +00:00
|
|
|
if (cache_sh_video && (err = forwarder->on_video(cache_sh_video)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "forward video sh");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
2017-09-23 14:12:33 +00:00
|
|
|
if (cache_sh_audio && (err = forwarder->on_audio(cache_sh_audio)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "forward audio sh");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsOriginHub::on_dvr_request_sh()
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2017-01-19 04:38:55 +00:00
|
|
|
|
|
|
|
SrsSharedPtrMessage* cache_metadata = source->meta->data();
|
|
|
|
SrsSharedPtrMessage* cache_sh_video = source->meta->vsh();
|
|
|
|
SrsSharedPtrMessage* cache_sh_audio = source->meta->ash();
|
|
|
|
|
|
|
|
// feed the dvr the metadata/sequence header,
|
|
|
|
// when reload to start dvr, dvr will never get the sequence header in stream,
|
|
|
|
// use the SrsSource.on_dvr_request_sh to push the sequence header to DVR.
|
2017-09-23 14:12:33 +00:00
|
|
|
if (cache_metadata && (err = dvr->on_meta_data(cache_metadata)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "dvr metadata");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-06-04 07:10:35 +00:00
|
|
|
if (cache_sh_video) {
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = dvr->on_video(cache_sh_video, source->meta->vsh_format())) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "dvr video");
|
2017-06-04 07:10:35 +00:00
|
|
|
}
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
2017-06-04 07:10:35 +00:00
|
|
|
|
|
|
|
if (cache_sh_audio) {
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = dvr->on_audio(cache_sh_audio, source->meta->ash_format())) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "dvr audio");
|
2017-06-04 07:10:35 +00:00
|
|
|
}
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 08:14:30 +00:00
|
|
|
srs_error_t SrsOriginHub::on_reload_vhost_forward(string vhost)
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
2017-09-22 08:14:30 +00:00
|
|
|
srs_error_t err = srs_success;
|
2017-01-19 04:38:55 +00:00
|
|
|
|
|
|
|
if (req->vhost != vhost) {
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: FIXME: maybe should ignore when publish already stopped?
|
|
|
|
|
|
|
|
// forwarders
|
|
|
|
destroy_forwarders();
|
2017-02-09 06:29:57 +00:00
|
|
|
|
|
|
|
// Don't start forwarders when source is not active.
|
2017-02-09 06:33:56 +00:00
|
|
|
if (!is_active) {
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2017-02-09 06:29:57 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = create_forwarders()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "create forwarders");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
srs_trace("vhost %s forwarders reload success", vhost.c_str());
|
|
|
|
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 08:14:30 +00:00
|
|
|
srs_error_t SrsOriginHub::on_reload_vhost_dash(string vhost)
|
2017-02-11 13:14:28 +00:00
|
|
|
{
|
2017-09-22 08:14:30 +00:00
|
|
|
srs_error_t err = srs_success;
|
2017-02-11 13:14:28 +00:00
|
|
|
|
|
|
|
if (req->vhost != vhost) {
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2017-02-11 13:14:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dash->on_unpublish();
|
|
|
|
|
|
|
|
// Don't start DASH when source is not active.
|
|
|
|
if (!is_active) {
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2017-02-11 13:14:28 +00:00
|
|
|
}
|
|
|
|
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = dash->on_publish()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "dash start publish");
|
2017-02-11 13:14:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsSharedPtrMessage* cache_sh_video = source->meta->vsh();
|
2017-02-19 13:48:32 +00:00
|
|
|
if (cache_sh_video) {
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = format->on_video(cache_sh_video)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "format on_video");
|
2017-02-19 13:48:32 +00:00
|
|
|
}
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = dash->on_video(cache_sh_video, format)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "dash on_video");
|
2017-02-19 13:48:32 +00:00
|
|
|
}
|
2017-02-11 13:14:28 +00:00
|
|
|
}
|
2017-02-19 13:48:32 +00:00
|
|
|
|
|
|
|
SrsSharedPtrMessage* cache_sh_audio = source->meta->ash();
|
|
|
|
if (cache_sh_audio) {
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = format->on_audio(cache_sh_audio)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "format on_audio");
|
2017-02-19 13:48:32 +00:00
|
|
|
}
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = dash->on_audio(cache_sh_audio, format)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "dash on_audio");
|
2017-02-19 13:48:32 +00:00
|
|
|
}
|
2017-02-11 13:14:28 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2017-02-11 13:14:28 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 08:14:30 +00:00
|
|
|
srs_error_t SrsOriginHub::on_reload_vhost_hls(string vhost)
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
2017-09-22 08:14:30 +00:00
|
|
|
srs_error_t err = srs_success;
|
2017-01-19 04:38:55 +00:00
|
|
|
|
|
|
|
if (req->vhost != vhost) {
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2015-08-25 14:59:17 +00:00
|
|
|
// TODO: FIXME: maybe should ignore when publish already stopped?
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
hls->on_unpublish();
|
2017-02-09 06:29:57 +00:00
|
|
|
|
2017-02-11 13:14:28 +00:00
|
|
|
// Don't start HLS when source is not active.
|
2017-02-09 06:33:56 +00:00
|
|
|
if (!is_active) {
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2017-02-09 06:29:57 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 13:50:54 +00:00
|
|
|
if ((err = hls->on_publish()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "hls publish failed");
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
srs_trace("vhost %s hls reload success", vhost.c_str());
|
|
|
|
|
2017-02-11 13:14:28 +00:00
|
|
|
// when publish, don't need to fetch sequence header, which is old and maybe corrupt.
|
|
|
|
// when reload, we must fetch the sequence header from source cache.
|
|
|
|
// notice the source to get the cached sequence header.
|
|
|
|
// 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.
|
|
|
|
SrsSharedPtrMessage* cache_sh_video = source->meta->vsh();
|
2017-02-19 13:48:32 +00:00
|
|
|
if (cache_sh_video) {
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = format->on_video(cache_sh_video)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "format on_video");
|
2017-02-19 13:48:32 +00:00
|
|
|
}
|
2017-09-22 13:50:54 +00:00
|
|
|
if ((err = hls->on_video(cache_sh_video, format)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "hls on_video");
|
2017-02-19 13:48:32 +00:00
|
|
|
}
|
2017-02-11 13:14:28 +00:00
|
|
|
}
|
2017-02-19 13:48:32 +00:00
|
|
|
|
|
|
|
SrsSharedPtrMessage* cache_sh_audio = source->meta->ash();
|
|
|
|
if (cache_sh_audio) {
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = format->on_audio(cache_sh_audio)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "format on_audio");
|
2017-02-19 13:48:32 +00:00
|
|
|
}
|
2017-09-22 13:50:54 +00:00
|
|
|
if ((err = hls->on_audio(cache_sh_audio, format)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "hls on_audio");
|
2017-02-19 13:48:32 +00:00
|
|
|
}
|
2017-02-11 13:14:28 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2013-12-15 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 08:14:30 +00:00
|
|
|
srs_error_t SrsOriginHub::on_reload_vhost_hds(string vhost)
|
2015-03-12 14:38:11 +00:00
|
|
|
{
|
2017-09-22 08:14:30 +00:00
|
|
|
srs_error_t err = srs_success;
|
2017-01-19 04:38:55 +00:00
|
|
|
|
2015-09-15 07:58:57 +00:00
|
|
|
if (req->vhost != vhost) {
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2015-03-12 14:38:11 +00:00
|
|
|
}
|
2015-08-25 14:59:17 +00:00
|
|
|
|
|
|
|
// TODO: FIXME: maybe should ignore when publish already stopped?
|
2017-01-19 04:38:55 +00:00
|
|
|
|
2020-04-29 12:02:28 +00:00
|
|
|
#ifdef SRS_HDS
|
2015-03-12 14:38:11 +00:00
|
|
|
hds->on_unpublish();
|
2017-02-09 06:29:57 +00:00
|
|
|
|
2017-02-11 13:14:28 +00:00
|
|
|
// Don't start HDS when source is not active.
|
2017-02-09 06:33:56 +00:00
|
|
|
if (!is_active) {
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2017-02-09 06:29:57 +00:00
|
|
|
}
|
|
|
|
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = hds->on_publish(req)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "hds publish failed");
|
2015-03-12 14:38:11 +00:00
|
|
|
}
|
|
|
|
srs_trace("vhost %s hds reload success", vhost.c_str());
|
|
|
|
#endif
|
2017-01-19 04:38:55 +00:00
|
|
|
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2015-03-12 14:38:11 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 08:14:30 +00:00
|
|
|
srs_error_t SrsOriginHub::on_reload_vhost_dvr(string vhost)
|
2014-04-17 08:22:21 +00:00
|
|
|
{
|
2017-06-11 01:40:07 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-04-17 08:22:21 +00:00
|
|
|
|
2015-09-15 07:58:57 +00:00
|
|
|
if (req->vhost != vhost) {
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2014-04-17 08:22:21 +00:00
|
|
|
}
|
|
|
|
|
2015-08-25 14:59:17 +00:00
|
|
|
// TODO: FIXME: maybe should ignore when publish already stopped?
|
|
|
|
|
2014-04-17 08:57:04 +00:00
|
|
|
// cleanup dvr
|
2014-04-17 08:22:21 +00:00
|
|
|
dvr->on_unpublish();
|
2017-01-19 04:38:55 +00:00
|
|
|
|
2017-02-11 13:14:28 +00:00
|
|
|
// Don't start DVR when source is not active.
|
2017-02-09 06:33:56 +00:00
|
|
|
if (!is_active) {
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2017-02-09 06:29:57 +00:00
|
|
|
}
|
|
|
|
|
2014-04-17 08:57:04 +00:00
|
|
|
// reinitialize the dvr, update plan.
|
2017-06-11 01:40:07 +00:00
|
|
|
if ((err = dvr->initialize(this, req)) != srs_success) {
|
2017-09-22 08:14:30 +00:00
|
|
|
return srs_error_wrap(err, "reload dvr");
|
2014-04-17 08:57:04 +00:00
|
|
|
}
|
2017-01-19 04:38:55 +00:00
|
|
|
|
2014-04-17 08:57:04 +00:00
|
|
|
// start to publish by new plan.
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = dvr->on_publish()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "dvr publish failed");
|
2014-04-17 08:22:21 +00:00
|
|
|
}
|
2014-04-17 08:57:04 +00:00
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = on_dvr_request_sh()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "request sh");
|
2017-02-11 13:14:28 +00:00
|
|
|
}
|
|
|
|
|
2014-04-17 08:22:21 +00:00
|
|
|
srs_trace("vhost %s dvr reload success", vhost.c_str());
|
|
|
|
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2014-04-17 08:22:21 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 08:14:30 +00:00
|
|
|
srs_error_t SrsOriginHub::on_reload_vhost_transcode(string vhost)
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
2017-09-22 08:14:30 +00:00
|
|
|
srs_error_t err = srs_success;
|
2017-01-19 04:38:55 +00:00
|
|
|
|
|
|
|
if (req->vhost != vhost) {
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: FIXME: maybe should ignore when publish already stopped?
|
|
|
|
|
|
|
|
encoder->on_unpublish();
|
2017-02-09 06:29:57 +00:00
|
|
|
|
2017-02-11 13:14:28 +00:00
|
|
|
// Don't start transcode when source is not active.
|
2017-02-09 06:33:56 +00:00
|
|
|
if (!is_active) {
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2017-02-09 06:29:57 +00:00
|
|
|
}
|
|
|
|
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = encoder->on_publish(req)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "start encoder failed");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
srs_trace("vhost %s transcode reload success", vhost.c_str());
|
|
|
|
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 08:14:30 +00:00
|
|
|
srs_error_t SrsOriginHub::on_reload_vhost_exec(string vhost)
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
2017-09-22 08:14:30 +00:00
|
|
|
srs_error_t err = srs_success;
|
2017-01-19 04:38:55 +00:00
|
|
|
|
|
|
|
if (req->vhost != vhost) {
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: FIXME: maybe should ignore when publish already stopped?
|
|
|
|
|
|
|
|
ng_exec->on_unpublish();
|
2017-02-09 06:33:56 +00:00
|
|
|
|
2017-02-11 13:14:28 +00:00
|
|
|
// Don't start exec when source is not active.
|
2017-02-09 06:33:56 +00:00
|
|
|
if (!is_active) {
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2017-02-09 06:33:56 +00:00
|
|
|
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = ng_exec->on_publish(req)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "start exec failed");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
srs_trace("vhost %s exec reload success", vhost.c_str());
|
|
|
|
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsOriginHub::create_forwarders()
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2017-01-19 04:38:55 +00:00
|
|
|
|
|
|
|
if (!_srs_config->get_forward_enabled(req->vhost)) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsConfDirective* conf = _srs_config->get_forwards(req->vhost);
|
|
|
|
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);
|
|
|
|
|
|
|
|
// initialize the forwarder with request.
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = forwarder->initialize(req, forward_server)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "init forwarder");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
2019-04-15 23:55:19 +00:00
|
|
|
|
|
|
|
srs_utime_t queue_size = _srs_config->get_queue_length(req->vhost);
|
2018-08-02 01:17:49 +00:00
|
|
|
forwarder->set_queue_size(queue_size);
|
2017-01-19 04:38:55 +00:00
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = forwarder->on_publish()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "start forwarder failed, vhost=%s, app=%s, stream=%s, forward-to=%s",
|
|
|
|
req->vhost.c_str(), req->app.c_str(), req->stream.c_str(), forward_server.c_str());
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsOriginHub::destroy_forwarders()
|
|
|
|
{
|
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
|
|
|
forwarder->on_unpublish();
|
|
|
|
srs_freep(forwarder);
|
|
|
|
}
|
|
|
|
forwarders.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsMetaCache::SrsMetaCache()
|
|
|
|
{
|
2017-01-19 07:51:34 +00:00
|
|
|
meta = video = audio = NULL;
|
2020-03-12 03:55:37 +00:00
|
|
|
previous_video = previous_audio = NULL;
|
2017-06-04 11:35:52 +00:00
|
|
|
vformat = new SrsRtmpFormat();
|
|
|
|
aformat = new SrsRtmpFormat();
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsMetaCache::~SrsMetaCache()
|
|
|
|
{
|
|
|
|
dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsMetaCache::dispose()
|
2020-03-12 03:55:37 +00:00
|
|
|
{
|
|
|
|
clear();
|
|
|
|
srs_freep(previous_video);
|
|
|
|
srs_freep(previous_audio);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsMetaCache::clear()
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
2017-01-19 07:51:34 +00:00
|
|
|
srs_freep(meta);
|
|
|
|
srs_freep(video);
|
|
|
|
srs_freep(audio);
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsSharedPtrMessage* SrsMetaCache::data()
|
|
|
|
{
|
2017-01-19 07:51:34 +00:00
|
|
|
return meta;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsSharedPtrMessage* SrsMetaCache::vsh()
|
|
|
|
{
|
2017-01-19 07:51:34 +00:00
|
|
|
return video;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-06-04 11:35:52 +00:00
|
|
|
SrsFormat* SrsMetaCache::vsh_format()
|
|
|
|
{
|
|
|
|
return vformat;
|
|
|
|
}
|
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
SrsSharedPtrMessage* SrsMetaCache::ash()
|
|
|
|
{
|
2017-01-19 07:51:34 +00:00
|
|
|
return audio;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-06-04 11:35:52 +00:00
|
|
|
SrsFormat* SrsMetaCache::ash_format()
|
|
|
|
{
|
|
|
|
return aformat;
|
|
|
|
}
|
|
|
|
|
2020-05-15 00:24:26 +00:00
|
|
|
srs_error_t SrsMetaCache::dumps(SrsConsumer* consumer, bool atc, SrsRtmpJitterAlgorithm ag, bool dm, bool ds)
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2017-01-19 04:38:55 +00:00
|
|
|
|
|
|
|
// copy metadata.
|
2017-09-23 14:12:33 +00:00
|
|
|
if (dm && meta && (err = consumer->enqueue(meta, atc, ag)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "enqueue metadata");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// copy sequence header
|
|
|
|
// copy audio sequence first, for hls to fast parse the "right" audio codec.
|
|
|
|
// @see https://github.com/ossrs/srs/issues/301
|
2017-09-23 14:12:33 +00:00
|
|
|
if (ds && audio && (err = consumer->enqueue(audio, atc, ag)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "enqueue audio sh");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
if (ds && video && (err = consumer->enqueue(video, atc, ag)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "enqueue video sh");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2020-03-12 03:55:37 +00:00
|
|
|
SrsSharedPtrMessage* SrsMetaCache::previous_vsh()
|
|
|
|
{
|
|
|
|
return previous_video;
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsSharedPtrMessage* SrsMetaCache::previous_ash()
|
|
|
|
{
|
|
|
|
return previous_audio;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsMetaCache::update_previous_vsh()
|
|
|
|
{
|
|
|
|
srs_freep(previous_video);
|
|
|
|
previous_video = video? video->copy() : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsMetaCache::update_previous_ash()
|
|
|
|
{
|
|
|
|
srs_freep(previous_audio);
|
|
|
|
previous_audio = audio? audio->copy() : NULL;
|
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsMetaCache::update_data(SrsMessageHeader* header, SrsOnMetaDataPacket* metadata, bool& updated)
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
|
|
|
updated = false;
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2017-01-19 04:38:55 +00:00
|
|
|
|
|
|
|
SrsAmf0Any* prop = NULL;
|
|
|
|
|
|
|
|
// when exists the duration, remove it to make ExoPlayer happy.
|
|
|
|
if (metadata->metadata->get_property("duration") != NULL) {
|
|
|
|
metadata->metadata->remove("duration");
|
|
|
|
}
|
|
|
|
|
|
|
|
// generate metadata info to print
|
|
|
|
std::stringstream ss;
|
|
|
|
if ((prop = metadata->metadata->ensure_property_number("width")) != NULL) {
|
|
|
|
ss << ", width=" << (int)prop->to_number();
|
|
|
|
}
|
|
|
|
if ((prop = metadata->metadata->ensure_property_number("height")) != NULL) {
|
|
|
|
ss << ", height=" << (int)prop->to_number();
|
|
|
|
}
|
|
|
|
if ((prop = metadata->metadata->ensure_property_number("videocodecid")) != NULL) {
|
|
|
|
ss << ", vcodec=" << (int)prop->to_number();
|
|
|
|
}
|
|
|
|
if ((prop = metadata->metadata->ensure_property_number("audiocodecid")) != NULL) {
|
|
|
|
ss << ", acodec=" << (int)prop->to_number();
|
|
|
|
}
|
|
|
|
srs_trace("got metadata%s", ss.str().c_str());
|
|
|
|
|
|
|
|
// add server info to metadata
|
|
|
|
metadata->metadata->set("server", SrsAmf0Any::str(RTMP_SIG_SRS_SERVER));
|
2019-04-30 00:38:57 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// version, for example, 1.0.0
|
|
|
|
// add version to metadata, please donot remove it, for debug.
|
|
|
|
metadata->metadata->set("server_version", SrsAmf0Any::str(RTMP_SIG_SRS_VERSION));
|
|
|
|
|
|
|
|
// encode the metadata to payload
|
|
|
|
int size = 0;
|
|
|
|
char* payload = NULL;
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = metadata->encode(size, payload)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "encode metadata");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (size <= 0) {
|
|
|
|
srs_warn("ignore the invalid metadata. size=%d", size);
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// create a shared ptr message.
|
2017-01-19 07:51:34 +00:00
|
|
|
srs_freep(meta);
|
|
|
|
meta = new SrsSharedPtrMessage();
|
2017-01-19 04:38:55 +00:00
|
|
|
updated = true;
|
|
|
|
|
|
|
|
// dump message to shared ptr message.
|
|
|
|
// the payload/size managed by cache_metadata, user should not free it.
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = meta->create(header, payload, size)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "create metadata");
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsMetaCache::update_ash(SrsSharedPtrMessage* msg)
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
2017-01-19 07:51:34 +00:00
|
|
|
srs_freep(audio);
|
|
|
|
audio = msg->copy();
|
2020-03-12 03:55:37 +00:00
|
|
|
update_previous_ash();
|
2017-06-04 11:35:52 +00:00
|
|
|
return aformat->on_audio(msg);
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsMetaCache::update_vsh(SrsSharedPtrMessage* msg)
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
2017-01-19 07:51:34 +00:00
|
|
|
srs_freep(video);
|
|
|
|
video = msg->copy();
|
2020-03-12 03:55:37 +00:00
|
|
|
update_previous_vsh();
|
2017-06-04 11:35:52 +00:00
|
|
|
return vformat->on_video(msg);
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2020-01-16 09:56:55 +00:00
|
|
|
SrsSourceManager* _srs_sources = new SrsSourceManager();
|
2017-01-19 04:38:55 +00:00
|
|
|
|
2020-01-16 09:56:55 +00:00
|
|
|
SrsSourceManager::SrsSourceManager()
|
|
|
|
{
|
2020-01-28 13:35:06 +00:00
|
|
|
lock = NULL;
|
2020-01-16 09:56:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsSourceManager::~SrsSourceManager()
|
|
|
|
{
|
2020-01-28 13:35:06 +00:00
|
|
|
srs_mutex_destroy(lock);
|
2020-01-16 09:56:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
srs_error_t SrsSourceManager::fetch_or_create(SrsRequest* r, ISrsSourceHandler* h, SrsSource** pps)
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
2017-06-11 01:40:07 +00:00
|
|
|
srs_error_t err = srs_success;
|
2020-01-28 13:35:06 +00:00
|
|
|
|
|
|
|
// Lazy create lock, because ST is not ready in SrsSourceManager constructor.
|
|
|
|
if (!lock) {
|
|
|
|
lock = srs_mutex_new();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Use lock to protect coroutine switch.
|
|
|
|
// @bug https://github.com/ossrs/srs/issues/1230
|
2020-05-12 11:53:21 +00:00
|
|
|
// TODO: FIXME: Use smaller lock.
|
2020-01-28 13:35:06 +00:00
|
|
|
SrsLocker(lock);
|
2017-01-19 04:38:55 +00:00
|
|
|
|
|
|
|
SrsSource* source = NULL;
|
|
|
|
if ((source = fetch(r)) != NULL) {
|
|
|
|
*pps = source;
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string stream_url = r->get_stream_url();
|
|
|
|
string vhost = r->vhost;
|
|
|
|
|
|
|
|
// should always not exists for create a source.
|
|
|
|
srs_assert (pool.find(stream_url) == pool.end());
|
2020-03-09 11:46:27 +00:00
|
|
|
|
2020-05-12 11:53:21 +00:00
|
|
|
#ifdef SRS_RTC
|
|
|
|
bool rtc_server_enabled = _srs_config->get_rtc_server_enabled();
|
|
|
|
bool rtc_enabled = _srs_config->get_rtc_enabled(r->vhost);
|
|
|
|
|
|
|
|
// Get the RTC source and bridger.
|
2020-07-08 11:01:33 +00:00
|
|
|
SrsRtcStream* rtc = NULL;
|
2020-05-12 11:53:21 +00:00
|
|
|
if (rtc_server_enabled && rtc_enabled) {
|
|
|
|
if ((err = _srs_rtc_sources->fetch_or_create(r, &rtc)) != srs_success) {
|
|
|
|
err = srs_error_wrap(err, "init rtc %s", r->get_stream_url().c_str());
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2020-03-09 11:46:27 +00:00
|
|
|
srs_trace("new source, stream_url=%s", stream_url.c_str());
|
2020-05-12 11:53:21 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
source = new SrsSource();
|
2017-06-11 01:40:07 +00:00
|
|
|
if ((err = source->initialize(r, h)) != srs_success) {
|
2020-05-12 11:53:21 +00:00
|
|
|
err = srs_error_wrap(err, "init source %s", r->get_stream_url().c_str());
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef SRS_RTC
|
|
|
|
// If rtc enabled, bridge RTMP source to RTC,
|
|
|
|
// all RTMP packets will be forwarded to RTC source.
|
|
|
|
if (source && rtc) {
|
|
|
|
source->bridge_to(rtc->bridger());
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
2020-05-12 11:53:21 +00:00
|
|
|
#endif
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
pool[stream_url] = source;
|
|
|
|
*pps = source;
|
2020-05-12 11:53:21 +00:00
|
|
|
return err;
|
|
|
|
|
|
|
|
failed:
|
|
|
|
srs_freep(source);
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2020-01-16 09:56:55 +00:00
|
|
|
SrsSource* SrsSourceManager::fetch(SrsRequest* r)
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
|
|
|
SrsSource* source = NULL;
|
|
|
|
|
|
|
|
string stream_url = r->get_stream_url();
|
|
|
|
if (pool.find(stream_url) == pool.end()) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
source = pool[stream_url];
|
2017-03-25 09:21:39 +00:00
|
|
|
|
|
|
|
// we always update the request of resource,
|
2017-01-19 04:38:55 +00:00
|
|
|
// for origin auth is on, the token in request maybe invalid,
|
|
|
|
// and we only need to update the token of request, it's simple.
|
2020-01-16 09:56:55 +00:00
|
|
|
source->update_auth(r);
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
return source;
|
|
|
|
}
|
|
|
|
|
2020-01-16 09:56:55 +00:00
|
|
|
void SrsSourceManager::dispose()
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
|
|
|
std::map<std::string, SrsSource*>::iterator it;
|
|
|
|
for (it = pool.begin(); it != pool.end(); ++it) {
|
|
|
|
SrsSource* source = it->second;
|
|
|
|
source->dispose();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-16 09:56:55 +00:00
|
|
|
srs_error_t SrsSourceManager::cycle()
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
2020-07-05 15:26:55 +00:00
|
|
|
SrsContextId cid = _srs_context->get_id();
|
2020-01-16 09:56:55 +00:00
|
|
|
srs_error_t err = do_cycle();
|
2017-01-19 04:38:55 +00:00
|
|
|
_srs_context->set_id(cid);
|
|
|
|
|
2017-06-11 01:40:07 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2020-01-16 09:56:55 +00:00
|
|
|
srs_error_t SrsSourceManager::do_cycle()
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
2017-06-11 01:40:07 +00:00
|
|
|
srs_error_t err = srs_success;
|
2017-01-19 04:38:55 +00:00
|
|
|
|
|
|
|
std::map<std::string, SrsSource*>::iterator it;
|
|
|
|
for (it = pool.begin(); it != pool.end();) {
|
|
|
|
SrsSource* source = it->second;
|
|
|
|
|
|
|
|
// Do cycle source to cleanup components, such as hls dispose.
|
2017-06-11 01:40:07 +00:00
|
|
|
if ((err = source->cycle()) != srs_success) {
|
2020-06-18 03:45:43 +00:00
|
|
|
return srs_error_wrap(err, "source=%s/%s cycle", source->source_id().c_str(), source->pre_source_id().c_str());
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: FIXME: support source cleanup.
|
|
|
|
// @see https://github.com/ossrs/srs/issues/713
|
|
|
|
// @see https://github.com/ossrs/srs/issues/714
|
|
|
|
#if 0
|
|
|
|
// When source expired, remove it.
|
|
|
|
if (source->expired()) {
|
|
|
|
int cid = source->source_id();
|
|
|
|
if (cid == -1 && source->pre_source_id() > 0) {
|
|
|
|
cid = source->pre_source_id();
|
|
|
|
}
|
|
|
|
if (cid > 0) {
|
|
|
|
_srs_context->set_id(cid);
|
|
|
|
}
|
|
|
|
srs_trace("cleanup die source, total=%d", (int)pool.size());
|
|
|
|
|
|
|
|
srs_freep(source);
|
|
|
|
pool.erase(it++);
|
|
|
|
} else {
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
++it;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-06-11 01:40:07 +00:00
|
|
|
return err;
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
|
|
|
|
2020-01-16 09:56:55 +00:00
|
|
|
void SrsSourceManager::destroy()
|
2017-01-19 04:38:55 +00:00
|
|
|
{
|
|
|
|
std::map<std::string, SrsSource*>::iterator it;
|
|
|
|
for (it = pool.begin(); it != pool.end(); ++it) {
|
|
|
|
SrsSource* source = it->second;
|
|
|
|
srs_freep(source);
|
|
|
|
}
|
|
|
|
pool.clear();
|
|
|
|
}
|
|
|
|
|
2020-05-12 11:53:21 +00:00
|
|
|
ISrsSourceBridger::ISrsSourceBridger()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ISrsSourceBridger::~ISrsSourceBridger()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
SrsSource::SrsSource()
|
|
|
|
{
|
|
|
|
req = NULL;
|
|
|
|
jitter_algorithm = SrsRtmpJitterAlgorithmOFF;
|
|
|
|
mix_correct = false;
|
|
|
|
mix_queue = new SrsMixQueue();
|
|
|
|
|
|
|
|
_can_publish = true;
|
2019-04-10 01:07:03 +00:00
|
|
|
die_at = 0;
|
2020-05-12 11:53:21 +00:00
|
|
|
|
|
|
|
handler = NULL;
|
|
|
|
bridger = NULL;
|
2017-01-19 04:38:55 +00:00
|
|
|
|
|
|
|
play_edge = new SrsPlayEdge();
|
|
|
|
publish_edge = new SrsPublishEdge();
|
|
|
|
gop_cache = new SrsGopCache();
|
2017-02-11 13:14:28 +00:00
|
|
|
hub = new SrsOriginHub();
|
2017-01-19 04:38:55 +00:00
|
|
|
meta = new SrsMetaCache();
|
|
|
|
|
|
|
|
is_monotonically_increase = false;
|
|
|
|
last_packet_time = 0;
|
|
|
|
|
|
|
|
_srs_config->subscribe(this);
|
|
|
|
atc = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsSource::~SrsSource()
|
|
|
|
{
|
|
|
|
_srs_config->unsubscribe(this);
|
|
|
|
|
2017-03-25 09:21:39 +00:00
|
|
|
// never free the consumers,
|
2017-01-19 04:38:55 +00:00
|
|
|
// for all consumers are auto free.
|
|
|
|
consumers.clear();
|
|
|
|
|
|
|
|
srs_freep(hub);
|
|
|
|
srs_freep(meta);
|
|
|
|
srs_freep(mix_queue);
|
|
|
|
|
|
|
|
srs_freep(play_edge);
|
|
|
|
srs_freep(publish_edge);
|
|
|
|
srs_freep(gop_cache);
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
srs_freep(req);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsSource::dispose()
|
|
|
|
{
|
|
|
|
hub->dispose();
|
|
|
|
meta->dispose();
|
|
|
|
gop_cache->dispose();
|
|
|
|
}
|
|
|
|
|
2017-06-11 01:40:07 +00:00
|
|
|
srs_error_t SrsSource::cycle()
|
2013-12-15 05:07:39 +00:00
|
|
|
{
|
2017-06-11 01:40:07 +00:00
|
|
|
srs_error_t err = hub->cycle();
|
|
|
|
if (err != srs_success) {
|
|
|
|
return srs_error_wrap(err, "hub cycle");
|
|
|
|
}
|
|
|
|
|
|
|
|
return srs_success;
|
2013-12-15 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
bool SrsSource::expired()
|
2015-08-25 14:29:00 +00:00
|
|
|
{
|
2017-01-19 04:38:55 +00:00
|
|
|
// unknown state?
|
2019-04-10 01:07:03 +00:00
|
|
|
if (die_at == 0) {
|
2017-01-19 04:38:55 +00:00
|
|
|
return false;
|
|
|
|
}
|
2015-08-25 14:29:00 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// still publishing?
|
|
|
|
if (!_can_publish || !publish_edge->can_publish()) {
|
|
|
|
return false;
|
2015-08-25 14:29:00 +00:00
|
|
|
}
|
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// has any consumers?
|
|
|
|
if (!consumers.empty()) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-08-25 14:59:17 +00:00
|
|
|
|
2019-04-10 01:07:03 +00:00
|
|
|
srs_utime_t now = srs_get_system_time();
|
2017-01-19 04:38:55 +00:00
|
|
|
if (now > die_at + SRS_SOURCE_CLEANUP) {
|
|
|
|
return true;
|
2015-08-25 14:29:00 +00:00
|
|
|
}
|
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
return false;
|
2015-08-25 14:29:00 +00:00
|
|
|
}
|
|
|
|
|
2017-06-11 01:40:07 +00:00
|
|
|
srs_error_t SrsSource::initialize(SrsRequest* r, ISrsSourceHandler* h)
|
2013-12-15 09:09:25 +00:00
|
|
|
{
|
2017-06-11 01:40:07 +00:00
|
|
|
srs_error_t err = srs_success;
|
2017-01-19 04:38:55 +00:00
|
|
|
|
|
|
|
srs_assert(h);
|
|
|
|
srs_assert(!req);
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
handler = h;
|
|
|
|
req = r->copy();
|
|
|
|
atc = _srs_config->get_atc(req->vhost);
|
|
|
|
|
2017-06-11 01:40:07 +00:00
|
|
|
if ((err = hub->initialize(this, req)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "hub");
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2017-06-11 01:40:07 +00:00
|
|
|
if ((err = play_edge->initialize(this, req)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "edge(play)");
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2017-06-11 01:40:07 +00:00
|
|
|
if ((err = publish_edge->initialize(this, req)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "edge(publish)");
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2019-04-15 23:55:19 +00:00
|
|
|
srs_utime_t queue_size = _srs_config->get_queue_length(req->vhost);
|
2017-01-19 04:38:55 +00:00
|
|
|
publish_edge->set_queue_size(queue_size);
|
|
|
|
|
|
|
|
jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_time_jitter(req->vhost);
|
|
|
|
mix_correct = _srs_config->get_mix_correct(req->vhost);
|
|
|
|
|
2017-06-11 01:40:07 +00:00
|
|
|
return err;
|
2013-12-15 09:09:25 +00:00
|
|
|
}
|
|
|
|
|
2020-05-12 11:59:46 +00:00
|
|
|
void SrsSource::bridge_to(ISrsSourceBridger* v)
|
2020-05-12 11:53:21 +00:00
|
|
|
{
|
|
|
|
bridger = v;
|
|
|
|
}
|
|
|
|
|
2017-09-22 08:14:30 +00:00
|
|
|
srs_error_t SrsSource::on_reload_vhost_play(string vhost)
|
2013-12-15 12:29:18 +00:00
|
|
|
{
|
2017-09-22 08:14:30 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
if (req->vhost != vhost) {
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2014-04-17 08:06:49 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// time_jitter
|
|
|
|
jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_time_jitter(req->vhost);
|
2014-04-17 08:06:49 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// mix_correct
|
|
|
|
if (true) {
|
|
|
|
bool v = _srs_config->get_mix_correct(req->vhost);
|
2014-04-17 08:06:49 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// when changed, clear the mix queue.
|
|
|
|
if (v != mix_correct) {
|
|
|
|
mix_queue->clear();
|
2014-04-17 08:06:49 +00:00
|
|
|
}
|
2017-01-19 04:38:55 +00:00
|
|
|
mix_correct = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
// atc changed.
|
|
|
|
if (true) {
|
|
|
|
bool v = _srs_config->get_atc(vhost);
|
2014-04-17 08:06:49 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
if (v != atc) {
|
|
|
|
srs_warn("vhost %s atc changed to %d, connected client may corrupt.", vhost.c_str(), v);
|
|
|
|
gop_cache->clear();
|
2014-04-17 08:06:49 +00:00
|
|
|
}
|
2017-01-19 04:38:55 +00:00
|
|
|
atc = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
// gop cache changed.
|
|
|
|
if (true) {
|
|
|
|
bool v = _srs_config->get_gop_cache(vhost);
|
2014-04-17 08:06:49 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
if (v != gop_cache->enabled()) {
|
|
|
|
string url = req->get_stream_url();
|
|
|
|
srs_trace("vhost %s gop_cache changed to %d, source url=%s", vhost.c_str(), v, url.c_str());
|
|
|
|
gop_cache->set(v);
|
2014-04-17 08:06:49 +00:00
|
|
|
}
|
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// queue length
|
|
|
|
if (true) {
|
2019-04-15 23:55:19 +00:00
|
|
|
srs_utime_t v = _srs_config->get_queue_length(req->vhost);
|
2017-01-19 04:38:55 +00:00
|
|
|
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsConsumer*>::iterator it;
|
|
|
|
|
|
|
|
for (it = consumers.begin(); it != consumers.end(); ++it) {
|
|
|
|
SrsConsumer* consumer = *it;
|
|
|
|
consumer->set_queue_size(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_trace("consumers reload queue size success.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: FIXME: https://github.com/ossrs/srs/issues/742#issuecomment-273656897
|
|
|
|
// TODO: FIXME: support queue size.
|
|
|
|
#if 0
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
|
|
|
forwarder->set_queue_size(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_trace("forwarders reload queue size success.");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (true) {
|
|
|
|
publish_edge->set_queue_size(v);
|
|
|
|
srs_trace("publish_edge reload queue size success.");
|
|
|
|
}
|
2013-12-15 12:29:18 +00:00
|
|
|
#endif
|
2017-01-19 04:38:55 +00:00
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2017-09-22 08:14:30 +00:00
|
|
|
return err;
|
2013-12-15 12:29:18 +00:00
|
|
|
}
|
|
|
|
|
2020-07-05 15:26:55 +00:00
|
|
|
srs_error_t SrsSource::on_source_id_changed(SrsContextId id)
|
2014-05-27 09:59:59 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-05-27 09:59:59 +00:00
|
|
|
|
2020-07-05 15:49:47 +00:00
|
|
|
if (!_source_id.compare(id)) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2014-05-27 09:59:59 +00:00
|
|
|
}
|
2020-10-31 09:42:20 +00:00
|
|
|
|
2020-07-05 15:26:55 +00:00
|
|
|
if (_pre_source_id.empty()) {
|
2016-09-05 06:13:37 +00:00
|
|
|
_pre_source_id = id;
|
|
|
|
}
|
2014-05-27 09:59:59 +00:00
|
|
|
_source_id = id;
|
|
|
|
|
2014-05-27 11:18:31 +00:00
|
|
|
// notice all consumer
|
|
|
|
std::vector<SrsConsumer*>::iterator it;
|
|
|
|
for (it = consumers.begin(); it != consumers.end(); ++it) {
|
|
|
|
SrsConsumer* consumer = *it;
|
|
|
|
consumer->update_source_id();
|
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2014-05-27 09:59:59 +00:00
|
|
|
}
|
|
|
|
|
2020-07-05 15:26:55 +00:00
|
|
|
SrsContextId SrsSource::source_id()
|
2014-05-27 09:59:59 +00:00
|
|
|
{
|
|
|
|
return _source_id;
|
|
|
|
}
|
|
|
|
|
2020-07-05 15:26:55 +00:00
|
|
|
SrsContextId SrsSource::pre_source_id()
|
2016-09-05 06:13:37 +00:00
|
|
|
{
|
|
|
|
return _pre_source_id;
|
|
|
|
}
|
|
|
|
|
2018-02-16 08:39:07 +00:00
|
|
|
bool SrsSource::inactive()
|
|
|
|
{
|
|
|
|
return _can_publish;
|
|
|
|
}
|
|
|
|
|
2020-01-16 09:56:55 +00:00
|
|
|
void SrsSource::update_auth(SrsRequest* r)
|
|
|
|
{
|
|
|
|
req->update_auth(r);
|
|
|
|
}
|
|
|
|
|
2015-07-08 09:08:29 +00:00
|
|
|
bool SrsSource::can_publish(bool is_edge)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2015-07-08 09:08:29 +00:00
|
|
|
if (is_edge) {
|
|
|
|
return publish_edge->can_publish();
|
|
|
|
}
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2015-07-08 09:08:29 +00:00
|
|
|
return _can_publish;
|
2015-07-08 07:43:09 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-04-30 04:08:11 +00:00
|
|
|
// if allow atc_auto and bravo-atc detected, open atc for vhost.
|
2017-01-19 04:38:55 +00:00
|
|
|
SrsAmf0Any* prop = NULL;
|
2015-09-15 07:58:57 +00:00
|
|
|
atc = _srs_config->get_atc(req->vhost);
|
|
|
|
if (_srs_config->get_atc_auto(req->vhost)) {
|
2014-04-30 04:08:11 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// Update the meta cache.
|
|
|
|
bool updated = false;
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = meta->update_data(&msg->header, metadata, updated)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "update metadata");
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2017-01-19 04:38:55 +00:00
|
|
|
if (!updated) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2014-04-29 06:44:07 +00:00
|
|
|
}
|
|
|
|
|
2015-08-19 06:23:12 +00:00
|
|
|
// when already got metadata, drop when reduce sequence header.
|
|
|
|
bool drop_for_reduce = false;
|
2017-01-19 04:38:55 +00:00
|
|
|
if (meta->data() && _srs_config->get_reduce_sequence_header(req->vhost)) {
|
2015-08-19 06:23:12 +00:00
|
|
|
drop_for_reduce = true;
|
2015-08-19 07:14:26 +00:00
|
|
|
srs_warn("drop for reduce sh metadata, size=%d", msg->size);
|
2015-08-19 06:23:12 +00:00
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// copy to all consumer
|
2015-08-19 06:20:31 +00:00
|
|
|
if (!drop_for_reduce) {
|
2014-03-18 03:32:58 +00:00
|
|
|
std::vector<SrsConsumer*>::iterator it;
|
2017-01-19 04:38:55 +00:00
|
|
|
for (it = consumers.begin(); it != consumers.end(); ++it) {
|
|
|
|
SrsConsumer* consumer = *it;
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = consumer->enqueue(meta->data(), atc, jitter_algorithm)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "consume metadata");
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// Copy to hub to all utilities.
|
2017-02-11 15:09:23 +00:00
|
|
|
return hub->on_meta_data(meta->data(), metadata);
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsSource::on_audio(SrsCommonMessage* shared_audio)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2015-06-06 14:04:24 +00:00
|
|
|
// monotically increase detect.
|
|
|
|
if (!mix_correct && is_monotonically_increase) {
|
|
|
|
if (last_packet_time > 0 && shared_audio->header.timestamp < last_packet_time) {
|
|
|
|
is_monotonically_increase = false;
|
2015-08-05 14:54:29 +00:00
|
|
|
srs_warn("AUDIO: stream not monotonically increase, please open mix_correct.");
|
2015-06-06 14:04:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
last_packet_time = shared_audio->header.timestamp;
|
|
|
|
|
2015-03-21 03:55:28 +00:00
|
|
|
// convert shared_audio to msg, user should not use shared_audio again.
|
|
|
|
// the payload is transfer to msg, and set to NULL in shared_audio.
|
2014-07-06 10:23:14 +00:00
|
|
|
SrsSharedPtrMessage msg;
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = msg.create(shared_audio)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "create message");
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2015-06-06 12:23:18 +00:00
|
|
|
// directly process the audio message.
|
2015-04-15 09:12:22 +00:00
|
|
|
if (!mix_correct) {
|
|
|
|
return on_audio_imp(&msg);
|
|
|
|
}
|
2015-04-15 08:17:52 +00:00
|
|
|
|
2015-06-06 12:23:18 +00:00
|
|
|
// insert msg to the queue.
|
|
|
|
mix_queue->push(msg.copy());
|
|
|
|
|
|
|
|
// fetch someone from mix queue.
|
|
|
|
SrsSharedPtrMessage* m = mix_queue->pop();
|
|
|
|
if (!m) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2015-06-06 12:23:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// consume the monotonically increase message.
|
2015-06-06 13:31:39 +00:00
|
|
|
if (m->is_audio()) {
|
2017-09-23 14:12:33 +00:00
|
|
|
err = on_audio_imp(m);
|
2015-06-06 13:31:39 +00:00
|
|
|
} else {
|
2017-09-23 14:12:33 +00:00
|
|
|
err = on_video_imp(m);
|
2015-06-06 13:31:39 +00:00
|
|
|
}
|
2015-06-06 12:23:18 +00:00
|
|
|
srs_freep(m);
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2015-04-15 08:17:52 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsSource::on_audio_imp(SrsSharedPtrMessage* msg)
|
2015-04-15 08:17:52 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2015-04-15 08:17:52 +00:00
|
|
|
|
2017-02-12 12:38:39 +00:00
|
|
|
bool is_aac_sequence_header = SrsFlvAudio::sh(msg->payload, msg->size);
|
2015-08-14 06:35:41 +00:00
|
|
|
bool is_sequence_header = is_aac_sequence_header;
|
2015-04-15 09:12:22 +00:00
|
|
|
|
2015-09-14 07:32:09 +00:00
|
|
|
// whether consumer should drop for the duplicated sequence header.
|
|
|
|
bool drop_for_reduce = false;
|
2020-03-12 03:55:37 +00:00
|
|
|
if (is_sequence_header && meta->previous_ash() && _srs_config->get_reduce_sequence_header(req->vhost)) {
|
|
|
|
if (meta->previous_ash()->size == msg->size) {
|
|
|
|
drop_for_reduce = srs_bytes_equals(meta->previous_ash()->payload, msg->payload, msg->size);
|
2015-09-14 07:32:09 +00:00
|
|
|
srs_warn("drop for reduce sh audio, size=%d", msg->size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-21 13:50:06 +00:00
|
|
|
// Copy to hub to all utilities.
|
|
|
|
if ((err = hub->on_audio(msg)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "consume audio");
|
|
|
|
}
|
|
|
|
|
2020-05-12 11:53:21 +00:00
|
|
|
// For bridger to consume the message.
|
|
|
|
if (bridger && (err = bridger->on_audio(msg)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "bridger consume audio");
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// copy to all consumer
|
2015-08-14 06:35:41 +00:00
|
|
|
if (!drop_for_reduce) {
|
|
|
|
for (int i = 0; i < (int)consumers.size(); i++) {
|
|
|
|
SrsConsumer* consumer = consumers.at(i);
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = consumer->enqueue(msg, atc, jitter_algorithm)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "consume message");
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-06-22 12:01:25 +00:00
|
|
|
|
2015-01-25 08:42:22 +00:00
|
|
|
// cache the sequence header of aac, or first packet of mp3.
|
|
|
|
// for example, the mp3 is used for hls to write the "right" audio codec.
|
2015-03-08 07:33:08 +00:00
|
|
|
// TODO: FIXME: to refine the stream info system.
|
2017-01-19 04:38:55 +00:00
|
|
|
if (is_aac_sequence_header || !meta->ash()) {
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = meta->update_ash(msg)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "meta consume audio");
|
2017-06-04 11:35:52 +00:00
|
|
|
}
|
2015-01-25 08:42:22 +00:00
|
|
|
}
|
2020-08-06 04:02:32 +00:00
|
|
|
|
2015-09-14 10:36:44 +00:00
|
|
|
// when sequence header, donot push to gop cache and adjust the timestamp.
|
|
|
|
if (is_sequence_header) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// cache the last gop packets
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = gop_cache->cache(msg)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "gop cache consume audio");
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2020-08-06 04:02:32 +00:00
|
|
|
|
2014-03-26 08:25:02 +00:00
|
|
|
// if atc, update the sequence header to abs time.
|
|
|
|
if (atc) {
|
2017-01-19 04:38:55 +00:00
|
|
|
if (meta->ash()) {
|
|
|
|
meta->ash()->timestamp = msg->timestamp;
|
2014-03-26 08:25:02 +00:00
|
|
|
}
|
2017-01-19 04:38:55 +00:00
|
|
|
if (meta->data()) {
|
|
|
|
meta->data()->timestamp = msg->timestamp;
|
2014-03-26 08:25:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsSource::on_video(SrsCommonMessage* shared_video)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2015-06-06 14:04:24 +00:00
|
|
|
// monotically increase detect.
|
|
|
|
if (!mix_correct && is_monotonically_increase) {
|
|
|
|
if (last_packet_time > 0 && shared_video->header.timestamp < last_packet_time) {
|
|
|
|
is_monotonically_increase = false;
|
2015-06-13 09:23:38 +00:00
|
|
|
srs_warn("VIDEO: stream not monotonically increase, please open mix_correct.");
|
2015-06-06 14:04:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
last_packet_time = shared_video->header.timestamp;
|
|
|
|
|
2015-06-06 13:23:57 +00:00
|
|
|
// drop any unknown header video.
|
2015-11-11 02:37:50 +00:00
|
|
|
// @see https://github.com/ossrs/srs/issues/421
|
2017-02-12 12:38:39 +00:00
|
|
|
if (!SrsFlvVideo::acceptable(shared_video->payload, shared_video->size)) {
|
2015-06-06 13:23:57 +00:00
|
|
|
char b0 = 0x00;
|
|
|
|
if (shared_video->size > 0) {
|
|
|
|
b0 = shared_video->payload[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_warn("drop unknown header video, size=%d, bytes[0]=%#x", shared_video->size, b0);
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2015-06-06 13:23:57 +00:00
|
|
|
}
|
|
|
|
|
2015-03-21 03:55:28 +00:00
|
|
|
// convert shared_video to msg, user should not use shared_video again.
|
|
|
|
// the payload is transfer to msg, and set to NULL in shared_video.
|
2014-07-06 10:23:14 +00:00
|
|
|
SrsSharedPtrMessage msg;
|
2018-01-01 11:39:57 +00:00
|
|
|
if ((err = msg.create(shared_video)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "create message");
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2020-03-08 11:20:46 +00:00
|
|
|
// directly process the video message.
|
2015-04-15 09:12:22 +00:00
|
|
|
if (!mix_correct) {
|
|
|
|
return on_video_imp(&msg);
|
|
|
|
}
|
2015-04-15 08:17:52 +00:00
|
|
|
|
2015-06-06 12:23:18 +00:00
|
|
|
// insert msg to the queue.
|
|
|
|
mix_queue->push(msg.copy());
|
|
|
|
|
|
|
|
// fetch someone from mix queue.
|
|
|
|
SrsSharedPtrMessage* m = mix_queue->pop();
|
|
|
|
if (!m) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2015-06-06 12:23:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// consume the monotonically increase message.
|
2015-06-06 13:31:39 +00:00
|
|
|
if (m->is_audio()) {
|
2017-09-23 14:12:33 +00:00
|
|
|
err = on_audio_imp(m);
|
2015-06-06 13:31:39 +00:00
|
|
|
} else {
|
2017-09-23 14:12:33 +00:00
|
|
|
err = on_video_imp(m);
|
2015-06-06 13:31:39 +00:00
|
|
|
}
|
2015-06-06 12:23:18 +00:00
|
|
|
srs_freep(m);
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2015-04-15 08:17:52 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsSource::on_video_imp(SrsSharedPtrMessage* msg)
|
2015-04-15 08:17:52 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2015-04-15 09:12:22 +00:00
|
|
|
|
2017-02-12 12:38:39 +00:00
|
|
|
bool is_sequence_header = SrsFlvVideo::sh(msg->payload, msg->size);
|
2015-08-14 06:35:41 +00:00
|
|
|
|
2015-09-14 07:32:09 +00:00
|
|
|
// whether consumer should drop for the duplicated sequence header.
|
|
|
|
bool drop_for_reduce = false;
|
2020-03-12 03:55:37 +00:00
|
|
|
if (is_sequence_header && meta->previous_vsh() && _srs_config->get_reduce_sequence_header(req->vhost)) {
|
|
|
|
if (meta->previous_vsh()->size == msg->size) {
|
|
|
|
drop_for_reduce = srs_bytes_equals(meta->previous_vsh()->payload, msg->payload, msg->size);
|
2015-09-14 07:32:09 +00:00
|
|
|
srs_warn("drop for reduce sh video, size=%d", msg->size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// cache the sequence header if h264
|
|
|
|
// donot cache the sequence header to gop_cache, return here.
|
2017-09-23 14:12:33 +00:00
|
|
|
if (is_sequence_header && (err = meta->update_vsh(msg)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "meta update video");
|
2015-09-14 07:32:09 +00:00
|
|
|
}
|
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// Copy to hub to all utilities.
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = hub->on_video(msg, is_sequence_header)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "hub consume video");
|
2015-03-11 05:34:58 +00:00
|
|
|
}
|
2020-03-13 12:34:40 +00:00
|
|
|
|
2020-05-12 11:53:21 +00:00
|
|
|
// For bridger to consume the message.
|
|
|
|
if (bridger && (err = bridger->on_video(msg)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "bridger consume video");
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// copy to all consumer
|
2015-08-14 06:35:41 +00:00
|
|
|
if (!drop_for_reduce) {
|
2014-06-22 12:01:25 +00:00
|
|
|
for (int i = 0; i < (int)consumers.size(); i++) {
|
|
|
|
SrsConsumer* consumer = consumers.at(i);
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = consumer->enqueue(msg, atc, jitter_algorithm)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "consume video");
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-06 04:02:32 +00:00
|
|
|
|
2015-09-14 10:36:44 +00:00
|
|
|
// when sequence header, donot push to gop cache and adjust the timestamp.
|
2015-08-14 06:35:41 +00:00
|
|
|
if (is_sequence_header) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2020-08-06 04:02:32 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// cache the last gop packets
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = gop_cache->cache(msg)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "gop cache consume vdieo");
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2020-08-06 04:02:32 +00:00
|
|
|
|
2014-03-26 08:25:02 +00:00
|
|
|
// if atc, update the sequence header to abs time.
|
|
|
|
if (atc) {
|
2017-01-19 04:38:55 +00:00
|
|
|
if (meta->vsh()) {
|
|
|
|
meta->vsh()->timestamp = msg->timestamp;
|
2014-03-26 08:25:02 +00:00
|
|
|
}
|
2017-01-19 04:38:55 +00:00
|
|
|
if (meta->data()) {
|
|
|
|
meta->data()->timestamp = msg->timestamp;
|
2014-03-26 08:25:02 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-06 04:02:32 +00:00
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsSource::on_aggregate(SrsCommonMessage* msg)
|
2014-05-08 06:33:25 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-05-08 06:33:25 +00:00
|
|
|
|
2018-01-01 11:39:57 +00:00
|
|
|
SrsBuffer* stream = new SrsBuffer(msg->payload, msg->size);
|
|
|
|
SrsAutoFree(SrsBuffer, stream);
|
2014-05-08 06:33:25 +00:00
|
|
|
|
2015-01-07 07:37:44 +00:00
|
|
|
// the aggregate message always use abs time.
|
|
|
|
int delta = -1;
|
|
|
|
|
2014-05-08 06:33:25 +00:00
|
|
|
while (!stream->empty()) {
|
|
|
|
if (!stream->require(1)) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return srs_error_new(ERROR_RTMP_AGGREGATE, "aggregate");
|
2014-05-08 06:33:25 +00:00
|
|
|
}
|
|
|
|
int8_t type = stream->read_1bytes();
|
|
|
|
|
|
|
|
if (!stream->require(3)) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return srs_error_new(ERROR_RTMP_AGGREGATE, "aggregate");
|
2014-05-08 06:33:25 +00:00
|
|
|
}
|
|
|
|
int32_t data_size = stream->read_3bytes();
|
|
|
|
|
|
|
|
if (data_size < 0) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return srs_error_new(ERROR_RTMP_AGGREGATE, "aggregate size");
|
2014-05-08 06:33:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!stream->require(3)) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return srs_error_new(ERROR_RTMP_AGGREGATE, "aggregate time");
|
2014-05-08 06:33:25 +00:00
|
|
|
}
|
|
|
|
int32_t timestamp = stream->read_3bytes();
|
|
|
|
|
|
|
|
if (!stream->require(1)) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return srs_error_new(ERROR_RTMP_AGGREGATE, "aggregate time(high bits)");
|
2014-05-08 06:33:25 +00:00
|
|
|
}
|
|
|
|
int32_t time_h = stream->read_1bytes();
|
|
|
|
|
|
|
|
timestamp |= time_h<<24;
|
|
|
|
timestamp &= 0x7FFFFFFF;
|
|
|
|
|
2015-01-07 07:37:44 +00:00
|
|
|
// adjust abs timestamp in aggregate msg.
|
2015-06-10 05:53:13 +00:00
|
|
|
// only -1 means uninitialized delta.
|
|
|
|
if (delta == -1) {
|
2015-01-07 07:37:44 +00:00
|
|
|
delta = (int)msg->header.timestamp - (int)timestamp;
|
|
|
|
}
|
|
|
|
timestamp += delta;
|
|
|
|
|
2014-05-08 06:33:25 +00:00
|
|
|
if (!stream->require(3)) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return srs_error_new(ERROR_RTMP_AGGREGATE, "aggregate stream id");
|
2014-05-08 06:33:25 +00:00
|
|
|
}
|
|
|
|
int32_t stream_id = stream->read_3bytes();
|
|
|
|
|
|
|
|
if (data_size > 0 && !stream->require(data_size)) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return srs_error_new(ERROR_RTMP_AGGREGATE, "aggregate data");
|
2014-05-08 06:33:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// to common message.
|
2015-03-21 03:55:28 +00:00
|
|
|
SrsCommonMessage o;
|
2014-05-08 06:33:25 +00:00
|
|
|
|
|
|
|
o.header.message_type = type;
|
|
|
|
o.header.payload_length = data_size;
|
|
|
|
o.header.timestamp_delta = timestamp;
|
|
|
|
o.header.timestamp = timestamp;
|
|
|
|
o.header.stream_id = stream_id;
|
|
|
|
o.header.perfer_cid = msg->header.perfer_cid;
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2014-05-08 06:33:25 +00:00
|
|
|
if (data_size > 0) {
|
|
|
|
o.size = data_size;
|
2014-07-11 10:08:34 +00:00
|
|
|
o.payload = new char[o.size];
|
|
|
|
stream->read_bytes(o.payload, o.size);
|
2014-05-08 06:33:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!stream->require(4)) {
|
2017-09-23 14:12:33 +00:00
|
|
|
return srs_error_new(ERROR_RTMP_AGGREGATE, "aggregate previous tag size");
|
2014-05-08 06:33:25 +00:00
|
|
|
}
|
|
|
|
stream->read_4bytes();
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2014-05-08 06:33:25 +00:00
|
|
|
// process parsed message
|
|
|
|
if (o.header.is_audio()) {
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = on_audio(&o)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "consume audio");
|
2014-05-08 06:33:25 +00:00
|
|
|
}
|
|
|
|
} else if (o.header.is_video()) {
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = on_video(&o)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "consume video");
|
2014-05-08 06:33:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2014-05-08 06:33:25 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsSource::on_publish()
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
// update the request object.
|
2015-09-15 07:58:57 +00:00
|
|
|
srs_assert(req);
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
_can_publish = false;
|
|
|
|
|
2014-05-27 09:59:59 +00:00
|
|
|
// whatever, the publish thread is the source or edge source,
|
|
|
|
// save its id to srouce id.
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = on_source_id_changed(_srs_context->get_id())) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "source id change");
|
2015-12-28 09:15:44 +00:00
|
|
|
}
|
2014-05-27 09:59:59 +00:00
|
|
|
|
2015-04-15 09:12:22 +00:00
|
|
|
// reset the mix queue.
|
|
|
|
mix_queue->clear();
|
2020-03-12 03:55:37 +00:00
|
|
|
|
|
|
|
// Reset the metadata cache, to make VLC happy when disable/enable stream.
|
|
|
|
// @see https://github.com/ossrs/srs/issues/1630#issuecomment-597979448
|
|
|
|
meta->clear();
|
2015-04-15 09:12:22 +00:00
|
|
|
|
2015-06-06 14:04:24 +00:00
|
|
|
// detect the monotonically again.
|
|
|
|
is_monotonically_increase = true;
|
|
|
|
last_packet_time = 0;
|
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// Notify the hub about the publish event.
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = hub->on_publish()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "hub publish");
|
2015-08-25 14:29:00 +00:00
|
|
|
}
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2015-01-18 10:39:53 +00:00
|
|
|
// notify the handler.
|
|
|
|
srs_assert(handler);
|
2017-09-23 14:12:33 +00:00
|
|
|
if ((err = handler->on_publish(this, req)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "handle publish");
|
2015-01-18 10:39:53 +00:00
|
|
|
}
|
2020-05-12 11:53:21 +00:00
|
|
|
|
|
|
|
if (bridger && (err = bridger->on_publish()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "bridger publish");
|
|
|
|
}
|
|
|
|
|
2015-05-08 08:45:25 +00:00
|
|
|
SrsStatistic* stat = SrsStatistic::instance();
|
2015-09-15 07:58:57 +00:00
|
|
|
stat->on_stream_publish(req, _source_id);
|
2015-09-14 07:10:34 +00:00
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsSource::on_unpublish()
|
|
|
|
{
|
2016-09-05 06:13:37 +00:00
|
|
|
// ignore when already unpublished.
|
|
|
|
if (_can_publish) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-19 04:38:55 +00:00
|
|
|
// Notify the hub about the unpublish event.
|
|
|
|
hub->on_unpublish();
|
2017-03-25 09:21:39 +00:00
|
|
|
|
2015-08-19 06:20:31 +00:00
|
|
|
// only clear the gop cache,
|
|
|
|
// donot clear the sequence header, for it maybe not changed,
|
|
|
|
// when drop dup sequence header, drop the metadata also.
|
2014-03-18 03:32:58 +00:00
|
|
|
gop_cache->clear();
|
2020-03-12 03:55:37 +00:00
|
|
|
|
|
|
|
// Reset the metadata cache, to make VLC happy when disable/enable stream.
|
|
|
|
// @see https://github.com/ossrs/srs/issues/1630#issuecomment-597979448
|
|
|
|
meta->update_previous_vsh();
|
|
|
|
meta->update_previous_ash();
|
|
|
|
|
2014-05-29 06:16:34 +00:00
|
|
|
srs_trace("cleanup when unpublish");
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
_can_publish = true;
|
2020-10-31 11:25:56 +00:00
|
|
|
if (!_source_id.empty()) {
|
2020-10-31 09:42:20 +00:00
|
|
|
_pre_source_id = _source_id;
|
|
|
|
}
|
2020-10-31 14:04:53 +00:00
|
|
|
_source_id = SrsContextId();
|
2020-10-31 11:25:56 +00:00
|
|
|
|
2015-01-18 10:39:53 +00:00
|
|
|
// notify the handler.
|
|
|
|
srs_assert(handler);
|
2015-05-08 08:45:25 +00:00
|
|
|
SrsStatistic* stat = SrsStatistic::instance();
|
2015-09-15 07:58:57 +00:00
|
|
|
stat->on_stream_close(req);
|
2020-05-12 11:53:21 +00:00
|
|
|
|
2015-09-15 07:58:57 +00:00
|
|
|
handler->on_unpublish(this, req);
|
2020-05-12 11:53:21 +00:00
|
|
|
|
|
|
|
if (bridger) {
|
|
|
|
bridger->on_unpublish();
|
|
|
|
}
|
2016-09-05 06:13:37 +00:00
|
|
|
|
|
|
|
// no consumer, stream is die.
|
|
|
|
if (consumers.empty()) {
|
2019-04-10 01:07:03 +00:00
|
|
|
die_at = srs_get_system_time();
|
2016-09-05 06:13:37 +00:00
|
|
|
}
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2020-09-11 09:03:48 +00:00
|
|
|
srs_error_t SrsSource::create_consumer(SrsConsumer*& consumer)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t err = srs_success;
|
2020-08-06 04:02:32 +00:00
|
|
|
|
2020-09-11 09:03:48 +00:00
|
|
|
consumer = new SrsConsumer(this);
|
2014-03-18 03:32:58 +00:00
|
|
|
consumers.push_back(consumer);
|
2020-08-06 04:02:32 +00:00
|
|
|
|
2020-05-02 23:43:05 +00:00
|
|
|
// for edge, when play edge stream, check the state
|
|
|
|
if (_srs_config->get_vhost_is_edge(req->vhost)) {
|
|
|
|
// notice edge to start for the first client.
|
|
|
|
if ((err = play_edge->on_client_play()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "play edge");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_error_t SrsSource::consumer_dumps(SrsConsumer* consumer, bool ds, bool dm, bool dg)
|
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
2020-01-27 11:46:08 +00:00
|
|
|
|
2019-04-15 23:55:19 +00:00
|
|
|
srs_utime_t queue_size = _srs_config->get_queue_length(req->vhost);
|
2014-03-18 03:32:58 +00:00
|
|
|
consumer->set_queue_size(queue_size);
|
2020-01-27 11:46:08 +00:00
|
|
|
|
2014-03-26 08:25:02 +00:00
|
|
|
// if atc, update the sequence header to gop cache time.
|
|
|
|
if (atc && !gop_cache->empty()) {
|
2017-01-19 04:38:55 +00:00
|
|
|
if (meta->data()) {
|
2019-04-19 00:04:09 +00:00
|
|
|
meta->data()->timestamp = srsu2ms(gop_cache->start_time());
|
2014-05-13 07:30:20 +00:00
|
|
|
}
|
2017-01-19 04:38:55 +00:00
|
|
|
if (meta->vsh()) {
|
2019-04-19 00:04:09 +00:00
|
|
|
meta->vsh()->timestamp = srsu2ms(gop_cache->start_time());
|
2014-03-26 08:25:02 +00:00
|
|
|
}
|
2017-01-19 04:38:55 +00:00
|
|
|
if (meta->ash()) {
|
2019-04-19 00:04:09 +00:00
|
|
|
meta->ash()->timestamp = srsu2ms(gop_cache->start_time());
|
2014-03-26 08:25:02 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-27 11:46:08 +00:00
|
|
|
|
|
|
|
// If stream is publishing, dumps the sequence header and gop cache.
|
|
|
|
if (hub->active()) {
|
|
|
|
// Copy metadata and sequence header to consumer.
|
|
|
|
if ((err = meta->dumps(consumer, atc, jitter_algorithm, dm, ds)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "meta dumps");
|
|
|
|
}
|
|
|
|
|
|
|
|
// copy gop cache to client.
|
|
|
|
if (dg && (err = gop_cache->dump(consumer, atc, jitter_algorithm)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "gop cache dumps");
|
|
|
|
}
|
2015-01-19 04:56:05 +00:00
|
|
|
}
|
2020-01-27 11:46:08 +00:00
|
|
|
|
2015-01-19 04:56:05 +00:00
|
|
|
// print status.
|
|
|
|
if (dg) {
|
2020-01-27 11:46:08 +00:00
|
|
|
srs_trace("create consumer, active=%d, queue_size=%.2f, jitter=%d", hub->active(), queue_size, jitter_algorithm);
|
2015-01-19 04:24:18 +00:00
|
|
|
} else {
|
2020-01-27 11:46:08 +00:00
|
|
|
srs_trace("create consumer, active=%d, ignore gop cache, jitter=%d", hub->active(), jitter_algorithm);
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2020-05-02 23:43:05 +00:00
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
return err;
|
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);
|
|
|
|
}
|
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();
|
2019-04-10 01:07:03 +00:00
|
|
|
die_at = srs_get_system_time();
|
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
|
|
|
}
|
|
|
|
|
2015-06-10 07:38:13 +00:00
|
|
|
SrsRtmpJitterAlgorithm SrsSource::jitter()
|
|
|
|
{
|
|
|
|
return jitter_algorithm;
|
|
|
|
}
|
|
|
|
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsSource::on_edge_start_publish()
|
2014-04-27 01:29:37 +00:00
|
|
|
{
|
|
|
|
return publish_edge->on_client_publish();
|
2014-04-25 08:35:03 +00:00
|
|
|
}
|
|
|
|
|
2019-04-16 23:56:28 +00:00
|
|
|
// TODO: FIXME: Use edge strategy pattern.
|
2017-09-23 14:12:33 +00:00
|
|
|
srs_error_t SrsSource::on_edge_proxy_publish(SrsCommonMessage* 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
|
|
|
}
|
|
|
|
|
2015-09-17 05:36:02 +00:00
|
|
|
string SrsSource::get_curr_origin()
|
|
|
|
{
|
|
|
|
return play_edge->get_curr_origin();
|
|
|
|
}
|
|
|
|
|