2019-12-05 19:20:12 +08:00
|
|
|
|
/*
|
2020-04-04 20:30:09 +08:00
|
|
|
|
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
2019-12-06 11:54:10 +08:00
|
|
|
|
*
|
2021-01-17 18:31:50 +08:00
|
|
|
|
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
|
2019-12-06 11:54:10 +08:00
|
|
|
|
*
|
2020-04-04 20:30:09 +08:00
|
|
|
|
* Use of this source code is governed by MIT license that can be found in the
|
|
|
|
|
* LICENSE file in the root of the source tree. All contributing project authors
|
|
|
|
|
* may be found in the AUTHORS file in the root of the source tree.
|
2019-12-06 11:54:10 +08:00
|
|
|
|
*/
|
2019-12-05 19:20:12 +08:00
|
|
|
|
|
2019-12-06 11:54:10 +08:00
|
|
|
|
#if defined(ENABLE_RTPPROXY)
|
2020-10-24 23:33:13 +08:00
|
|
|
|
#include "GB28181Process.h"
|
2019-12-05 19:20:12 +08:00
|
|
|
|
#include "RtpProcess.h"
|
2020-05-17 18:00:23 +08:00
|
|
|
|
#include "Http/HttpTSPlayer.h"
|
2022-11-29 11:07:13 +08:00
|
|
|
|
#include "Util/File.h"
|
|
|
|
|
#include "Common/config.h"
|
2020-10-24 23:33:13 +08:00
|
|
|
|
|
2022-02-02 20:34:50 +08:00
|
|
|
|
using namespace std;
|
|
|
|
|
using namespace toolkit;
|
|
|
|
|
|
2021-06-23 11:09:53 +08:00
|
|
|
|
static constexpr char kRtpAppName[] = "rtp";
|
|
|
|
|
//在创建_muxer对象前(也就是推流鉴权成功前),需要先缓存frame,这样可以防止丢包,提高体验
|
|
|
|
|
//但是同时需要控制缓冲长度,防止内存溢出。200帧数据,大概有10秒数据,应该足矣等待鉴权hook返回
|
|
|
|
|
static constexpr size_t kMaxCachedFrame = 200;
|
2019-12-05 19:20:12 +08:00
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
namespace mediakit {
|
2019-12-05 19:20:12 +08:00
|
|
|
|
|
2020-07-07 10:01:12 +08:00
|
|
|
|
RtpProcess::RtpProcess(const string &stream_id) {
|
2023-05-25 16:23:24 +08:00
|
|
|
|
_media_info.schema = kRtpAppName;
|
|
|
|
|
_media_info.vhost = DEFAULT_VHOST;
|
|
|
|
|
_media_info.app = kRtpAppName;
|
|
|
|
|
_media_info.stream = stream_id;
|
2019-12-05 19:20:12 +08:00
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
GET_CONFIG(string, dump_dir, RtpProxy::kDumpDir);
|
2019-12-05 19:20:12 +08:00
|
|
|
|
{
|
2023-12-02 19:49:28 +08:00
|
|
|
|
FILE *fp = !dump_dir.empty() ? File::create_file(File::absolutePath(_media_info.stream + ".rtp", dump_dir), "wb") : nullptr;
|
2020-10-24 23:33:13 +08:00
|
|
|
|
if (fp) {
|
|
|
|
|
_save_file_rtp.reset(fp, [](FILE *fp) {
|
2019-12-05 19:20:12 +08:00
|
|
|
|
fclose(fp);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2023-12-02 19:49:28 +08:00
|
|
|
|
FILE *fp = !dump_dir.empty() ? File::create_file(File::absolutePath(_media_info.stream + ".video", dump_dir), "wb") : nullptr;
|
2020-10-24 23:33:13 +08:00
|
|
|
|
if (fp) {
|
|
|
|
|
_save_file_video.reset(fp, [](FILE *fp) {
|
2019-12-05 19:20:12 +08:00
|
|
|
|
fclose(fp);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-01 16:05:23 +08:00
|
|
|
|
void RtpProcess::flush() {
|
2022-10-16 19:49:56 +08:00
|
|
|
|
if (_process) {
|
|
|
|
|
_process->flush();
|
|
|
|
|
}
|
2022-11-01 16:05:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RtpProcess::~RtpProcess() {
|
2020-10-24 23:33:13 +08:00
|
|
|
|
uint64_t duration = (_last_frame_time.createdTime() - _last_frame_time.elapsedTime()) / 1000;
|
2020-04-23 23:18:24 +08:00
|
|
|
|
WarnP(this) << "RTP推流器("
|
2022-09-07 11:06:39 +08:00
|
|
|
|
<< _media_info.shortUrl()
|
2020-04-23 23:18:24 +08:00
|
|
|
|
<< ")断开,耗时(s):" << duration;
|
|
|
|
|
|
|
|
|
|
//流量统计事件广播
|
|
|
|
|
GET_CONFIG(uint32_t, iFlowThreshold, General::kFlowThreshold);
|
2021-02-03 14:04:33 +08:00
|
|
|
|
if (_total_bytes >= iFlowThreshold * 1024) {
|
2023-06-11 22:07:15 +08:00
|
|
|
|
try {
|
2023-09-02 10:52:07 +08:00
|
|
|
|
NOTICE_EMIT(BroadcastFlowReportArgs, Broadcast::kBroadcastFlowReport, _media_info, _total_bytes, duration, false, *this);
|
2023-06-11 22:07:15 +08:00
|
|
|
|
} catch (std::exception &ex) {
|
|
|
|
|
WarnL << "Exception occurred: " << ex.what();
|
|
|
|
|
}
|
2019-12-05 19:20:12 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-08 17:13:39 +08:00
|
|
|
|
bool RtpProcess::inputRtp(bool is_udp, const Socket::Ptr &sock, const char *data, size_t len, const struct sockaddr *addr, uint64_t *dts_out) {
|
2023-02-28 22:23:30 +08:00
|
|
|
|
if (!isRtp(data, len)) {
|
|
|
|
|
WarnP(this) << "Not rtp packet";
|
2023-02-26 21:11:31 +08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-11-15 11:02:12 +08:00
|
|
|
|
if (!_auth_err.empty()) {
|
|
|
|
|
throw toolkit::SockException(toolkit::Err_other, _auth_err);
|
|
|
|
|
}
|
2022-10-31 17:53:20 +08:00
|
|
|
|
if (_sock != sock) {
|
|
|
|
|
// 第一次运行本函数
|
|
|
|
|
bool first = !_sock;
|
2020-04-23 23:33:58 +08:00
|
|
|
|
_sock = sock;
|
2022-05-10 10:44:12 +08:00
|
|
|
|
_addr.reset(new sockaddr_storage(*((sockaddr_storage *)addr)));
|
2022-10-31 17:53:20 +08:00
|
|
|
|
if (first) {
|
|
|
|
|
emitOnPublish();
|
|
|
|
|
}
|
2020-04-23 23:18:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
_total_bytes += len;
|
|
|
|
|
if (_save_file_rtp) {
|
2021-01-17 18:31:50 +08:00
|
|
|
|
uint16_t size = (uint16_t)len;
|
2019-12-05 19:20:12 +08:00
|
|
|
|
size = htons(size);
|
|
|
|
|
fwrite((uint8_t *) &size, 2, 1, _save_file_rtp.get());
|
2020-10-24 23:33:13 +08:00
|
|
|
|
fwrite((uint8_t *) data, len, 1, _save_file_rtp.get());
|
2019-12-05 19:20:12 +08:00
|
|
|
|
}
|
2020-10-24 23:33:13 +08:00
|
|
|
|
if (!_process) {
|
|
|
|
|
_process = std::make_shared<GB28181Process>(_media_info, this);
|
2020-03-06 13:00:06 +08:00
|
|
|
|
}
|
2020-11-14 23:11:28 +08:00
|
|
|
|
|
2022-09-03 15:53:01 +08:00
|
|
|
|
auto header = (RtpHeader *) data;
|
|
|
|
|
onRtp(ntohs(header->seq), ntohl(header->stamp), 0/*不发送sr,所以可以设置为0*/ , 90000/*ps/ts流时间戳按照90K采样率*/, len);
|
|
|
|
|
|
2020-11-14 23:11:28 +08:00
|
|
|
|
GET_CONFIG(string, dump_dir, RtpProxy::kDumpDir);
|
2021-06-23 11:02:39 +08:00
|
|
|
|
if (_muxer && !_muxer->isEnabled() && !dts_out && dump_dir.empty()) {
|
2020-11-14 23:11:28 +08:00
|
|
|
|
//无人访问、且不取时间戳、不导出调试文件时,我们可以直接丢弃数据
|
|
|
|
|
_last_frame_time.resetTime();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
bool ret = _process ? _process->inputRtp(is_udp, data, len) : false;
|
|
|
|
|
if (dts_out) {
|
|
|
|
|
*dts_out = _dts;
|
2019-12-05 19:20:12 +08:00
|
|
|
|
}
|
2020-10-24 23:33:13 +08:00
|
|
|
|
return ret;
|
2019-12-05 19:20:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-27 13:12:53 +08:00
|
|
|
|
bool RtpProcess::inputFrame(const Frame::Ptr &frame) {
|
2020-05-17 18:00:23 +08:00
|
|
|
|
_dts = frame->dts();
|
|
|
|
|
if (_save_file_video && frame->getTrackType() == TrackVideo) {
|
|
|
|
|
fwrite((uint8_t *) frame->data(), frame->size(), 1, _save_file_video.get());
|
2020-02-25 19:00:22 +08:00
|
|
|
|
}
|
2021-06-23 11:02:39 +08:00
|
|
|
|
if (_muxer) {
|
|
|
|
|
_last_frame_time.resetTime();
|
2021-09-27 13:12:53 +08:00
|
|
|
|
return _muxer->inputFrame(frame);
|
2021-06-23 11:02:39 +08:00
|
|
|
|
}
|
2021-09-27 13:12:53 +08:00
|
|
|
|
if (_cached_func.size() > kMaxCachedFrame) {
|
2022-06-18 21:06:18 +08:00
|
|
|
|
WarnL << "cached frame of track(" << frame->getCodecName() << ") is too much, now dropped, please check your on_publish hook url in config.ini file";
|
2021-09-27 13:12:53 +08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
auto frame_cached = Frame::getCacheAbleFrame(frame);
|
|
|
|
|
lock_guard<recursive_mutex> lck(_func_mtx);
|
|
|
|
|
_cached_func.emplace_back([this, frame_cached]() {
|
|
|
|
|
_last_frame_time.resetTime();
|
|
|
|
|
_muxer->inputFrame(frame_cached);
|
|
|
|
|
});
|
|
|
|
|
return true;
|
2020-02-25 19:00:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-27 13:12:53 +08:00
|
|
|
|
bool RtpProcess::addTrack(const Track::Ptr &track) {
|
2021-06-23 11:02:39 +08:00
|
|
|
|
if (_muxer) {
|
2021-09-27 13:12:53 +08:00
|
|
|
|
return _muxer->addTrack(track);
|
2021-06-23 11:02:39 +08:00
|
|
|
|
}
|
2021-09-27 13:12:53 +08:00
|
|
|
|
|
|
|
|
|
lock_guard<recursive_mutex> lck(_func_mtx);
|
|
|
|
|
_cached_func.emplace_back([this, track]() {
|
|
|
|
|
_muxer->addTrack(track);
|
|
|
|
|
});
|
|
|
|
|
return true;
|
2019-12-05 19:20:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-29 09:38:04 +08:00
|
|
|
|
void RtpProcess::addTrackCompleted() {
|
2021-06-23 11:02:39 +08:00
|
|
|
|
if (_muxer) {
|
|
|
|
|
_muxer->addTrackCompleted();
|
|
|
|
|
} else {
|
|
|
|
|
lock_guard<recursive_mutex> lck(_func_mtx);
|
|
|
|
|
_cached_func.emplace_back([this]() {
|
|
|
|
|
_muxer->addTrackCompleted();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RtpProcess::doCachedFunc() {
|
|
|
|
|
lock_guard<recursive_mutex> lck(_func_mtx);
|
|
|
|
|
for (auto &func : _cached_func) {
|
|
|
|
|
func();
|
|
|
|
|
}
|
|
|
|
|
_cached_func.clear();
|
2020-11-29 09:38:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-05 19:20:12 +08:00
|
|
|
|
bool RtpProcess::alive() {
|
2020-12-27 21:21:31 +08:00
|
|
|
|
if (_stop_rtp_check.load()) {
|
2021-03-16 11:30:51 +08:00
|
|
|
|
if(_last_check_alive.elapsedTime() > 5 * 60 * 1000){
|
|
|
|
|
//最多暂停5分钟的rtp超时检测,因为NAT映射有效期一般不会太长
|
|
|
|
|
_stop_rtp_check = false;
|
|
|
|
|
} else {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-12-27 21:21:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 15:37:34 +08:00
|
|
|
|
_last_check_alive.resetTime();
|
2021-01-19 16:05:38 +08:00
|
|
|
|
GET_CONFIG(uint64_t, timeoutSec, RtpProxy::kTimeoutSec)
|
2020-10-24 23:33:13 +08:00
|
|
|
|
if (_last_frame_time.elapsedTime() / 1000 < timeoutSec) {
|
2019-12-05 19:20:12 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-25 16:05:38 +08:00
|
|
|
|
void RtpProcess::setStopCheckRtp(bool is_check){
|
|
|
|
|
_stop_rtp_check = is_check;
|
2021-04-01 22:24:35 +08:00
|
|
|
|
if (!is_check) {
|
|
|
|
|
_last_frame_time.resetTime();
|
|
|
|
|
}
|
2020-12-25 16:05:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-02-17 22:43:45 +08:00
|
|
|
|
void RtpProcess::setOnlyAudio(bool only_audio){
|
|
|
|
|
_only_audio = only_audio;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
void RtpProcess::onDetach() {
|
|
|
|
|
if (_on_detach) {
|
2020-07-08 10:25:30 +08:00
|
|
|
|
_on_detach();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-01 17:27:27 +08:00
|
|
|
|
void RtpProcess::setOnDetach(function<void()> cb) {
|
|
|
|
|
_on_detach = std::move(cb);
|
2020-07-08 10:25:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-24 12:39:22 +08:00
|
|
|
|
string RtpProcess::get_peer_ip() {
|
2023-07-29 13:24:07 +08:00
|
|
|
|
try {
|
|
|
|
|
return _addr ? SockUtil::inet_ntoa((sockaddr *)_addr.get()) : "::";
|
|
|
|
|
} catch (std::exception &ex) {
|
2022-05-10 10:44:12 +08:00
|
|
|
|
return "::";
|
|
|
|
|
}
|
2019-12-05 19:20:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t RtpProcess::get_peer_port() {
|
2023-07-29 13:24:07 +08:00
|
|
|
|
try {
|
|
|
|
|
return _addr ? SockUtil::inet_port((sockaddr *)_addr.get()) : 0;
|
|
|
|
|
} catch (std::exception &ex) {
|
2022-05-10 10:44:12 +08:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2019-12-05 19:20:12 +08:00
|
|
|
|
}
|
2019-12-06 11:54:10 +08:00
|
|
|
|
|
2020-04-24 12:39:22 +08:00
|
|
|
|
string RtpProcess::get_local_ip() {
|
2023-07-29 13:24:07 +08:00
|
|
|
|
return _sock ? _sock->get_local_ip() : "::";
|
2020-04-23 23:18:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t RtpProcess::get_local_port() {
|
2023-07-29 13:24:07 +08:00
|
|
|
|
return _sock ? _sock->get_local_port() : 0;
|
2020-04-23 23:18:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
string RtpProcess::getIdentifier() const {
|
2023-05-25 16:23:24 +08:00
|
|
|
|
return _media_info.stream;
|
2020-04-23 23:18:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RtpProcess::emitOnPublish() {
|
|
|
|
|
weak_ptr<RtpProcess> weak_self = shared_from_this();
|
2022-03-12 13:19:21 +08:00
|
|
|
|
Broadcast::PublishAuthInvoker invoker = [weak_self](const string &err, const ProtocolOption &option) {
|
2021-06-23 11:02:39 +08:00
|
|
|
|
auto strong_self = weak_self.lock();
|
|
|
|
|
if (!strong_self) {
|
2020-04-23 23:18:24 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2022-10-31 17:53:20 +08:00
|
|
|
|
auto poller = strong_self->getOwnerPoller(MediaSource::NullMediaSource());
|
2022-08-11 18:36:17 +08:00
|
|
|
|
poller->async([weak_self, err, option]() {
|
|
|
|
|
auto strong_self = weak_self.lock();
|
|
|
|
|
if (!strong_self) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (err.empty()) {
|
2023-05-25 16:23:24 +08:00
|
|
|
|
strong_self->_muxer = std::make_shared<MultiMediaSourceMuxer>(strong_self->_media_info, 0.0f,
|
2022-08-11 18:36:17 +08:00
|
|
|
|
option);
|
2023-02-17 22:43:45 +08:00
|
|
|
|
if (strong_self->_only_audio) {
|
|
|
|
|
strong_self->_muxer->setOnlyAudio();
|
|
|
|
|
}
|
2022-08-11 18:36:17 +08:00
|
|
|
|
strong_self->_muxer->setMediaListener(strong_self);
|
|
|
|
|
strong_self->doCachedFunc();
|
|
|
|
|
InfoP(strong_self) << "允许RTP推流";
|
|
|
|
|
} else {
|
2023-11-15 11:02:12 +08:00
|
|
|
|
strong_self->_auth_err = err;
|
2022-08-11 18:36:17 +08:00
|
|
|
|
WarnP(strong_self) << "禁止RTP推流:" << err;
|
|
|
|
|
}
|
|
|
|
|
});
|
2020-04-23 23:18:24 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//触发推流鉴权事件
|
2023-09-02 10:52:07 +08:00
|
|
|
|
auto flag = NOTICE_EMIT(BroadcastMediaPublishArgs, Broadcast::kBroadcastMediaPublish, MediaOriginType::rtp_push, _media_info, invoker, *this);
|
2020-10-24 23:33:13 +08:00
|
|
|
|
if (!flag) {
|
2023-09-02 10:52:07 +08:00
|
|
|
|
// 该事件无人监听,默认不鉴权
|
2022-03-12 13:19:21 +08:00
|
|
|
|
invoker("", ProtocolOption());
|
2020-04-23 23:18:24 +08:00
|
|
|
|
}
|
2020-02-28 16:25:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:34:22 +08:00
|
|
|
|
MediaOriginType RtpProcess::getOriginType(MediaSource &sender) const{
|
|
|
|
|
return MediaOriginType::rtp_push;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string RtpProcess::getOriginUrl(MediaSource &sender) const {
|
2022-09-07 11:06:39 +08:00
|
|
|
|
return _media_info.getUrl();
|
2020-10-24 23:34:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-16 17:31:13 +08:00
|
|
|
|
std::shared_ptr<SockInfo> RtpProcess::getOriginSock(MediaSource &sender) const {
|
2020-10-24 23:34:22 +08:00
|
|
|
|
return const_cast<RtpProcess *>(this)->shared_from_this();
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-18 13:22:57 +08:00
|
|
|
|
toolkit::EventPoller::Ptr RtpProcess::getOwnerPoller(MediaSource &sender) {
|
2022-10-31 17:53:20 +08:00
|
|
|
|
if (_sock) {
|
|
|
|
|
return _sock->getPoller();
|
|
|
|
|
}
|
2023-05-25 16:23:24 +08:00
|
|
|
|
throw std::runtime_error("RtpProcess::getOwnerPoller failed:" + _media_info.stream);
|
2022-06-18 13:22:57 +08:00
|
|
|
|
}
|
2022-07-26 14:42:42 +08:00
|
|
|
|
|
2022-09-03 15:53:01 +08:00
|
|
|
|
float RtpProcess::getLossRate(MediaSource &sender, TrackType type) {
|
|
|
|
|
auto expected = getExpectedPacketsInterval();
|
|
|
|
|
if (!expected) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2023-05-02 20:40:40 +08:00
|
|
|
|
return getLostInterval() * 100 / expected;
|
2022-07-26 11:21:19 +08:00
|
|
|
|
}
|
2022-07-26 14:42:42 +08:00
|
|
|
|
|
2019-12-06 11:54:10 +08:00
|
|
|
|
}//namespace mediakit
|
2023-07-29 13:24:07 +08:00
|
|
|
|
#endif//defined(ENABLE_RTPPROXY)
|