ZLMediaKit/src/Rtsp/RtspSession.cpp

1203 lines
47 KiB
C++
Raw Normal View History

2019-08-08 19:01:45 +08:00
/*
2020-04-04 20:30:09 +08:00
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
2017-09-27 16:20:30 +08:00
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
2017-09-27 16:20:30 +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.
2017-04-01 16:35:56 +08:00
*/
2017-08-09 18:39:30 +08:00
2017-04-25 11:35:41 +08:00
#include <atomic>
#include <iomanip>
2017-05-02 17:15:12 +08:00
#include "Common/config.h"
2017-04-25 11:35:41 +08:00
#include "UDPServer.h"
2017-04-01 16:35:56 +08:00
#include "RtspSession.h"
2017-12-10 01:34:43 +08:00
#include "Util/MD5.h"
2018-09-20 15:43:49 +08:00
#include "Util/base64.h"
2019-06-11 18:31:34 +08:00
2018-10-24 17:17:55 +08:00
using namespace std;
using namespace toolkit;
2017-04-01 16:35:56 +08:00
2018-10-24 17:17:55 +08:00
namespace mediakit {
2017-04-01 16:35:56 +08:00
/**
* rtsp协议有多种方式传输rtp数据包4
* 1: rtp over udp ,rtp通过单独的udp端口传输
* 2: rtp over udp_multicast,rtp通过共享udp组播端口传输
* 3: rtp over tcp,rtsp信令tcp通道完成传输
* 4: rtp over httprtp over http
*
* rtp over http rtsp协议伪装成http协议以达到穿透防火墙的目的
* http请求至rtsp服务器http get请求
* http post请求
*
* http请求头中的x-sessioncookie键完成绑定
*
* http get请求用于接收rtprtcp和rtsp回复
* http post请求用于发送rtsp请求rtsp握手结束后可能会断开连接rtp发送
* http post请求中的content负载就是base64编码后的rtsp请求包
* rtsp请求伪装成http content负载发送至rtsp服务器rtsp服务器又把回复发送给第一次http get请求的tcp链接
* rtsp会话就是两次http请求
*
* zlmediakit在处理rtsp over http的请求时http poster中的content数据base64解码后转发给http getter处理
*/
//rtsp over http 情况下get请求实例在请求实例用于接收rtp数据包
static unordered_map<string, weak_ptr<RtspSession> > g_mapGetter;
//对g_mapGetter上锁保护
static recursive_mutex g_mtxGetter;
2018-12-17 15:21:23 +08:00
2020-07-10 10:42:23 +08:00
RtspSession::RtspSession(const Socket::Ptr &sock) : TcpSession(sock) {
2019-05-29 18:08:50 +08:00
DebugP(this);
2019-05-30 10:41:25 +08:00
GET_CONFIG(uint32_t,keep_alive_sec,Rtsp::kKeepAliveSecond);
2020-07-10 10:42:23 +08:00
sock->setSendTimeOutSecond(keep_alive_sec);
2017-04-01 16:35:56 +08:00
}
RtspSession::~RtspSession() {
2019-05-28 18:46:52 +08:00
DebugP(this);
2017-04-01 16:35:56 +08:00
}
2020-07-10 10:42:23 +08:00
void RtspSession::onError(const SockException &err) {
bool isPlayer = !_push_src;
uint64_t duration = _alive_ticker.createdTime() / 1000;
2019-12-29 15:38:29 +08:00
WarnP(this) << (isPlayer ? "RTSP播放器(" : "RTSP推流器(")
2020-07-10 10:42:23 +08:00
<< _media_info._vhost << "/"
<< _media_info._app << "/"
<< _media_info._streamid
2020-02-13 12:10:08 +08:00
<< ")断开:" << err.what()
<< ",耗时(s):" << duration;
2019-10-23 12:00:53 +08:00
2020-07-10 10:42:23 +08:00
if (_rtp_type == Rtsp::RTP_MULTICAST) {
2020-03-20 11:51:24 +08:00
//取消UDP端口监听
UDPServer::Instance().stopListenPeer(get_peer_ip().data(), this);
}
2017-04-01 16:35:56 +08:00
2020-03-20 11:51:24 +08:00
if (_http_x_sessioncookie.size() != 0) {
//移除http getter的弱引用记录
lock_guard<recursive_mutex> lock(g_mtxGetter);
g_mapGetter.erase(_http_x_sessioncookie);
}
//流量统计事件广播
2019-05-28 17:14:36 +08:00
GET_CONFIG(uint32_t,iFlowThreshold,General::kFlowThreshold);
if(_bytes_usage >= iFlowThreshold * 1024){
2020-07-10 10:42:23 +08:00
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _media_info, _bytes_usage, duration, isPlayer, static_cast<SockInfo &>(*this));
}
2017-04-01 16:35:56 +08:00
}
void RtspSession::onManager() {
2019-08-28 18:20:40 +08:00
GET_CONFIG(uint32_t,handshake_sec,Rtsp::kHandshakeSecond);
2019-05-29 18:24:35 +08:00
GET_CONFIG(uint32_t,keep_alive_sec,Rtsp::kKeepAliveSecond);
2020-07-10 10:42:23 +08:00
if (_alive_ticker.createdTime() > handshake_sec * 1000) {
if (_sessionid.size() == 0) {
2020-03-20 11:51:24 +08:00
shutdown(SockException(Err_timeout,"illegal connection"));
return;
}
}
if ((_rtp_type == Rtsp::RTP_UDP || _push_src ) && _alive_ticker.elapsedTime() > keep_alive_sec * 1000 && _enable_send_rtp) {
2020-03-20 11:51:24 +08:00
//如果是推流端或者rtp over udp类型的播放端那么就做超时检测
2019-05-29 18:08:50 +08:00
shutdown(SockException(Err_timeout,"rtp over udp session timeouted"));
return;
2020-03-20 11:51:24 +08:00
}
2017-04-01 16:35:56 +08:00
}
2020-07-10 10:42:23 +08:00
void RtspSession::onRecv(const Buffer::Ptr &buf) {
_alive_ticker.resetTime();
_bytes_usage += buf->size();
if (_on_recv) {
2020-03-20 11:51:24 +08:00
//http poster的请求数据转发给http getter处理
2020-07-10 10:42:23 +08:00
_on_recv(buf);
2020-03-20 11:51:24 +08:00
} else {
2020-07-10 10:42:23 +08:00
input(buf->data(), buf->size());
2020-03-20 11:51:24 +08:00
}
2018-12-17 15:21:23 +08:00
}
2018-09-20 18:44:32 +08:00
2018-12-17 15:21:23 +08:00
void RtspSession::onWholeRtspPacket(Parser &parser) {
2020-07-10 10:42:23 +08:00
string method = parser.Method(); //提取出请求命令字
_cseq = atoi(parser["CSeq"].data());
if(_content_base.empty() && method != "GET"){
_content_base = parser.Url();
_media_info.parse(parser.FullUrl());
_media_info._schema = RTSP_SCHEMA;
}
2017-04-01 16:35:56 +08:00
2020-03-20 11:51:24 +08:00
typedef void (RtspSession::*rtsp_request_handler)(const Parser &parser);
static unordered_map<string, rtsp_request_handler> s_cmd_functions;
static onceToken token( []() {
s_cmd_functions.emplace("OPTIONS",&RtspSession::handleReq_Options);
s_cmd_functions.emplace("DESCRIBE",&RtspSession::handleReq_Describe);
s_cmd_functions.emplace("ANNOUNCE",&RtspSession::handleReq_ANNOUNCE);
s_cmd_functions.emplace("RECORD",&RtspSession::handleReq_RECORD);
s_cmd_functions.emplace("SETUP",&RtspSession::handleReq_Setup);
s_cmd_functions.emplace("PLAY",&RtspSession::handleReq_Play);
s_cmd_functions.emplace("PAUSE",&RtspSession::handleReq_Pause);
s_cmd_functions.emplace("TEARDOWN",&RtspSession::handleReq_Teardown);
s_cmd_functions.emplace("GET",&RtspSession::handleReq_Get);
s_cmd_functions.emplace("POST",&RtspSession::handleReq_Post);
s_cmd_functions.emplace("SET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER);
s_cmd_functions.emplace("GET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER);
}, []() {});
2020-07-10 10:42:23 +08:00
auto it = s_cmd_functions.find(method);
2020-03-20 11:51:24 +08:00
if (it == s_cmd_functions.end()) {
2019-05-30 12:14:20 +08:00
sendRtspResponse("403 Forbidden");
2020-07-10 10:42:23 +08:00
shutdown(SockException(Err_shutdown,StrPrinter << "403 Forbidden:" << method));
2019-05-30 12:14:20 +08:00
return;
2020-03-20 11:51:24 +08:00
}
2019-05-30 12:14:20 +08:00
auto &fun = it->second;
try {
(this->*fun)(parser);
}catch (SockException &ex){
if(ex){
shutdown(ex);
}
}catch (exception &ex){
shutdown(SockException(Err_shutdown,ex.what()));
}
parser.Clear();
2018-09-20 18:44:32 +08:00
}
void RtspSession::onRtpPacket(const char *data, size_t len) {
2020-03-20 11:51:24 +08:00
uint8_t interleaved = data[1];
2021-01-31 19:18:17 +08:00
if (interleaved % 2 == 0) {
if (!_push_src) {
return;
}
2020-07-10 10:42:23 +08:00
auto track_idx = getTrackIndexByInterleaved(interleaved);
2021-01-31 19:19:24 +08:00
handleOneRtp(track_idx, _sdp_track[track_idx]->_type, _sdp_track[track_idx]->_samplerate, (uint8_t *) data + RtpPacket::kRtpTcpHeaderSize, len - RtpPacket::kRtpTcpHeaderSize);
2021-01-31 19:18:17 +08:00
} else {
2020-07-10 10:42:23 +08:00
auto track_idx = getTrackIndexByInterleaved(interleaved - 1);
2021-01-31 19:19:24 +08:00
onRtcpPacket(track_idx, _sdp_track[track_idx], data + RtpPacket::kRtpTcpHeaderSize, len - RtpPacket::kRtpTcpHeaderSize);
2020-03-20 11:51:24 +08:00
}
2018-09-20 18:44:32 +08:00
}
2021-01-31 19:18:17 +08:00
void RtspSession::onRtcpPacket(int track_idx, SdpTrack::Ptr &track, const char *data, size_t len){
auto rtcp_arr = RtcpHeader::loadFromBytes((char *) data, len);
for (auto &rtcp : rtcp_arr) {
_rtcp_context[track_idx]->onRtcp(rtcp);
}
}
2019-05-08 14:23:18 +08:00
2021-01-19 16:05:38 +08:00
ssize_t RtspSession::getContentLength(Parser &parser) {
2020-03-20 11:51:24 +08:00
if(parser.Method() == "POST"){
//http post请求的content数据部分是base64编码后的rtsp请求信令包
return remainDataSize();
}
return RtspSplitter::getContentLength(parser);
2017-04-01 16:35:56 +08:00
}
2019-05-30 12:14:20 +08:00
void RtspSession::handleReq_Options(const Parser &parser) {
2020-03-20 11:51:24 +08:00
//支持这些命令
sendRtspResponse("200 OK",{"Public" , "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, ANNOUNCE, RECORD, SET_PARAMETER, GET_PARAMETER"});
2017-04-01 16:35:56 +08:00
}
2019-05-30 12:14:20 +08:00
void RtspSession::handleReq_ANNOUNCE(const Parser &parser) {
auto src = dynamic_pointer_cast<RtspMediaSource>(MediaSource::find(RTSP_SCHEMA,
2020-07-10 10:42:23 +08:00
_media_info._vhost,
_media_info._app,
_media_info._streamid));
2020-03-20 11:51:24 +08:00
if(src){
sendRtspResponse("406 Not Acceptable", {"Content-Type", "text/plain"}, "Already publishing.");
2019-05-30 12:14:20 +08:00
string err = StrPrinter << "ANNOUNCE:"
<< "Already publishing:"
2020-07-10 10:42:23 +08:00
<< _media_info._vhost << " "
<< _media_info._app << " "
<< _media_info._streamid << endl;
2020-03-20 11:51:24 +08:00
throw SockException(Err_shutdown,err);
}
2018-12-14 18:13:05 +08:00
auto full_url = parser.FullUrl();
2020-09-26 09:39:38 +08:00
if(end_with(full_url,".sdp")){
//去除.sdp后缀防止EasyDarwin推流器强制添加.sdp后缀
2019-09-10 17:08:24 +08:00
full_url = full_url.substr(0,full_url.length() - 4);
2020-07-10 10:42:23 +08:00
_media_info.parse(full_url);
}
2020-07-10 10:42:23 +08:00
if(_media_info._app.empty() || _media_info._streamid.empty()){
2020-05-25 16:40:41 +08:00
//推流rtsp url必须最少两级(rtsp://host/app/stream_id)不允许莫名其妙的推流url
2021-01-31 19:18:17 +08:00
static constexpr auto err = "rtsp推流url非法,最少确保两级rtsp url";
sendRtspResponse("403 Forbidden", {"Content-Type", "text/plain"}, err);
throw SockException(Err_shutdown, StrPrinter << err << ":" << full_url);
2020-05-25 16:40:41 +08:00
}
SdpParser sdpParser(parser.Content());
2020-07-10 10:42:23 +08:00
_sessionid = makeRandStr(12);
_sdp_track = sdpParser.getAvailableTrack();
2021-01-31 19:18:17 +08:00
if (_sdp_track.empty()) {
//sdp无效
static constexpr auto err = "sdp中无有效track";
sendRtspResponse("403 Forbidden", {"Content-Type", "text/plain"}, err);
throw SockException(Err_shutdown,StrPrinter << err << ":" << full_url);
}
2021-01-31 19:55:47 +08:00
_rtcp_context.clear();
2021-01-31 19:18:17 +08:00
for (auto &track : _sdp_track) {
2021-01-31 19:55:47 +08:00
_rtcp_context.emplace_back(std::make_shared<RtcpContext>(track->_samplerate, true));
2021-01-31 19:18:17 +08:00
}
2020-07-10 10:42:23 +08:00
_push_src = std::make_shared<RtspMediaSourceImp>(_media_info._vhost, _media_info._app, _media_info._streamid);
_push_src->setListener(dynamic_pointer_cast<MediaSourceEvent>(shared_from_this()));
_push_src->setSdp(sdpParser.toString());
sendRtspResponse("200 OK",{"Content-Base", _content_base + "/"});
}
2019-05-30 12:14:20 +08:00
void RtspSession::handleReq_RECORD(const Parser &parser){
2020-07-10 10:42:23 +08:00
if (_sdp_track.empty() || parser["Session"] != _sessionid) {
2020-03-20 11:51:24 +08:00
send_SessionNotFound();
2020-07-10 10:42:23 +08:00
throw SockException(Err_shutdown, _sdp_track.empty() ? "can not find any availabe track when record" : "session not found when record");
2020-03-20 11:51:24 +08:00
}
2020-09-12 19:09:56 +08:00
auto onRes = [this](const string &err, bool enableHls, bool enableMP4){
2020-03-20 11:51:24 +08:00
bool authSuccess = err.empty();
if(!authSuccess){
sendRtspResponse("401 Unauthorized", {"Content-Type", "text/plain"}, err);
shutdown(SockException(Err_shutdown,StrPrinter << "401 Unauthorized:" << err));
return;
}
//设置转协议
2020-09-12 19:09:56 +08:00
_push_src->setProtocolTranslation(enableHls, enableMP4);
2020-03-20 11:51:24 +08:00
_StrPrinter rtp_info;
2020-07-10 10:42:23 +08:00
for(auto &track : _sdp_track){
2020-03-20 11:51:24 +08:00
if (track->_inited == false) {
//还有track没有setup
2019-05-29 18:08:50 +08:00
shutdown(SockException(Err_shutdown,"track not setuped"));
return;
2020-03-20 11:51:24 +08:00
}
2020-07-10 10:42:23 +08:00
rtp_info << "url=" << _content_base << "/" << track->_control_surffix << ",";
2020-03-20 11:51:24 +08:00
}
rtp_info.pop_back();
sendRtspResponse("200 OK", {"RTP-Info",rtp_info});
2020-07-10 10:42:23 +08:00
if(_rtp_type == Rtsp::RTP_TCP){
//如果是rtsp推流服务器并且是TCP推流设置socket flags,,这样能提升接收性能
setSocketFlags();
2020-03-20 11:51:24 +08:00
}
};
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
2020-09-12 19:09:56 +08:00
Broadcast::PublishAuthInvoker invoker = [weakSelf, onRes](const string &err, bool enableHls, bool enableMP4) {
2020-03-20 11:51:24 +08:00
auto strongSelf = weakSelf.lock();
2020-09-12 19:09:56 +08:00
if (!strongSelf) {
2020-03-20 11:51:24 +08:00
return;
}
2020-09-12 19:09:56 +08:00
strongSelf->async([weakSelf, onRes, err, enableHls, enableMP4]() {
2020-03-20 11:51:24 +08:00
auto strongSelf = weakSelf.lock();
2020-09-12 19:09:56 +08:00
if (!strongSelf) {
2020-03-20 11:51:24 +08:00
return;
}
2020-09-12 19:09:56 +08:00
onRes(err, enableHls, enableMP4);
2020-03-20 11:51:24 +08:00
});
};
//rtsp推流需要鉴权
2020-07-10 10:42:23 +08:00
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPublish, _media_info, invoker, static_cast<SockInfo &>(*this));
2020-03-20 11:51:24 +08:00
if(!flag){
//该事件无人监听,默认不鉴权
GET_CONFIG(bool,toHls,General::kPublishToHls);
GET_CONFIG(bool,toMP4,General::kPublishToMP4);
2020-09-12 19:09:56 +08:00
onRes("",toHls,toMP4);
}
}
2020-05-25 18:22:21 +08:00
void RtspSession::emitOnPlay(){
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
2020-05-25 18:22:21 +08:00
//url鉴权回调
auto onRes = [weakSelf](const string &err) {
auto strongSelf = weakSelf.lock();
if (!strongSelf) {
return;
}
if (!err.empty()) {
//播放url鉴权失败
strongSelf->sendRtspResponse("401 Unauthorized", {"Content-Type", "text/plain"}, err);
strongSelf->shutdown(SockException(Err_shutdown, StrPrinter << "401 Unauthorized:" << err));
return;
}
strongSelf->onAuthSuccess();
};
Broadcast::AuthInvoker invoker = [weakSelf, onRes](const string &err) {
auto strongSelf = weakSelf.lock();
if (!strongSelf) {
return;
}
strongSelf->async([onRes, err, weakSelf]() {
onRes(err);
});
};
//广播通用播放url鉴权事件
2020-07-10 10:42:23 +08:00
auto flag = _emit_on_play ? false : NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed, _media_info, invoker, static_cast<SockInfo &>(*this));
2020-05-25 18:22:21 +08:00
if (!flag) {
//该事件无人监听,默认不鉴权
onRes("");
}
//已经鉴权过了
_emit_on_play = true;
}
void RtspSession::handleReq_Describe(const Parser &parser) {
//该请求中的认证信息
auto authorization = parser["Authorization"];
2020-05-25 18:22:21 +08:00
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
//rtsp专属鉴权是否开启事件回调
onGetRealm invoker = [weakSelf, authorization](const string &realm) {
auto strongSelf = weakSelf.lock();
2020-05-25 18:22:21 +08:00
if (!strongSelf) {
//本对象已经销毁
return;
}
//切换到自己的线程然后执行
2020-05-25 18:22:21 +08:00
strongSelf->async([weakSelf, realm, authorization]() {
auto strongSelf = weakSelf.lock();
2020-05-25 18:22:21 +08:00
if (!strongSelf) {
//本对象已经销毁
return;
}
2020-05-25 18:22:21 +08:00
if (realm.empty()) {
//无需rtsp专属认证, 那么继续url通用鉴权认证(on_play)
strongSelf->emitOnPlay();
return;
}
2020-05-25 18:22:21 +08:00
//该流需要rtsp专属认证开启rtsp专属认证后将不再触发url通用鉴权认证(on_play)
strongSelf->_rtsp_realm = realm;
strongSelf->onAuthUser(realm, authorization);
});
};
2020-05-25 18:22:21 +08:00
if(_rtsp_realm.empty()){
//广播是否需要rtsp专属认证事件
2020-07-10 10:42:23 +08:00
if (!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnGetRtspRealm, _media_info, invoker, static_cast<SockInfo &>(*this))) {
2020-05-25 18:22:21 +08:00
//无人监听此事件,说明无需认证
invoker("");
}
}else{
invoker(_rtsp_realm);
}
}
2020-07-10 10:42:23 +08:00
void RtspSession::onAuthSuccess() {
TraceP(this);
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
2020-07-10 10:42:23 +08:00
MediaSource::findAsync(_media_info, weakSelf.lock(), [weakSelf](const MediaSource::Ptr &src){
auto strongSelf = weakSelf.lock();
if(!strongSelf){
return;
}
auto rtsp_src = dynamic_pointer_cast<RtspMediaSource>(src);
if (!rtsp_src) {
//未找到相应的MediaSource
2020-07-10 10:42:23 +08:00
string err = StrPrinter << "no such stream:" << strongSelf->_media_info._vhost << " " << strongSelf->_media_info._app << " " << strongSelf->_media_info._streamid;
strongSelf->send_StreamNotFound();
2019-05-29 18:08:50 +08:00
strongSelf->shutdown(SockException(Err_shutdown,err));
return;
}
2019-08-30 11:17:27 +08:00
//找到了相应的rtsp流
2020-07-10 10:42:23 +08:00
strongSelf->_sdp_track = SdpParser(rtsp_src->getSdp()).getAvailableTrack();
if (strongSelf->_sdp_track.empty()) {
//该流无效
2021-01-31 19:18:17 +08:00
WarnL << "sdp中无有效track该流无效:" << rtsp_src->getSdp();
strongSelf->send_StreamNotFound();
2019-09-20 10:36:37 +08:00
strongSelf->shutdown(SockException(Err_shutdown,"can not find any available track in sdp"));
return;
}
2021-01-31 19:56:18 +08:00
strongSelf->_rtcp_context.clear();
2021-01-31 19:18:17 +08:00
for (auto &track : strongSelf->_sdp_track) {
2021-01-31 19:55:47 +08:00
strongSelf->_rtcp_context.emplace_back(std::make_shared<RtcpContext>(track->_samplerate, false));
2021-01-31 19:18:17 +08:00
}
2020-07-10 10:42:23 +08:00
strongSelf->_sessionid = makeRandStr(12);
strongSelf->_play_src = rtsp_src;
for(auto &track : strongSelf->_sdp_track){
track->_ssrc = rtsp_src->getSsrc(track->_type);
track->_seq = rtsp_src->getSeqence(track->_type);
track->_time_stamp = rtsp_src->getTimeStamp(track->_type);
}
2018-10-29 15:02:18 +08:00
strongSelf->sendRtspResponse("200 OK",
2020-07-10 10:42:23 +08:00
{"Content-Base", strongSelf->_content_base + "/",
"x-Accept-Retransmit","our-retransmit",
"x-Accept-Dynamic-Rate","1"
},rtsp_src->getSdp());
});
2017-04-01 16:35:56 +08:00
}
2020-07-10 10:42:23 +08:00
2019-05-30 12:14:20 +08:00
void RtspSession::onAuthFailed(const string &realm,const string &why,bool close) {
GET_CONFIG(bool,authBasic,Rtsp::kAuthBasic);
if (!authBasic) {
//我们需要客户端优先以md5方式认证
2020-07-10 10:42:23 +08:00
_auth_nonce = makeRandStr(32);
2019-05-30 12:14:20 +08:00
sendRtspResponse("401 Unauthorized",
{"WWW-Authenticate",
2020-07-10 10:42:23 +08:00
StrPrinter << "Digest realm=\"" << realm << "\",nonce=\"" << _auth_nonce << "\"" });
2019-05-30 12:14:20 +08:00
}else {
//当然我们也支持base64认证,但是我们不建议这样做
sendRtspResponse("401 Unauthorized",
{"WWW-Authenticate",
StrPrinter << "Basic realm=\"" << realm << "\"" });
}
if(close){
shutdown(SockException(Err_shutdown,StrPrinter << "401 Unauthorized:" << why));
2017-12-10 01:34:43 +08:00
}
}
2020-07-10 10:42:23 +08:00
void RtspSession::onAuthBasic(const string &realm,const string &auth_base64){
2017-12-10 01:34:43 +08:00
//base64认证
char user_pwd_buf[512];
av_base64_decode((uint8_t *) user_pwd_buf, auth_base64.data(), (int)auth_base64.size());
2020-07-10 10:42:23 +08:00
auto user_pwd_vec = split(user_pwd_buf, ":");
if (user_pwd_vec.size() < 2) {
2017-12-10 01:34:43 +08:00
//认证信息格式不合法回复401 Unauthorized
2020-07-10 10:42:23 +08:00
onAuthFailed(realm, "can not find user and passwd when basic64 auth");
2017-12-10 01:34:43 +08:00
return;
}
auto user = user_pwd_vec[0];
auto pwd = user_pwd_vec[1];
2019-05-30 12:14:20 +08:00
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
2020-07-10 10:42:23 +08:00
onAuth invoker = [pwd, realm, weakSelf](bool encrypted, const string &good_pwd) {
2019-05-30 12:14:20 +08:00
auto strongSelf = weakSelf.lock();
2020-07-10 10:42:23 +08:00
if (!strongSelf) {
2019-05-30 12:14:20 +08:00
//本对象已经销毁
return;
2017-12-10 01:34:43 +08:00
}
2019-05-30 12:14:20 +08:00
//切换到自己的线程执行
2020-07-10 10:42:23 +08:00
strongSelf->async([weakSelf, good_pwd, pwd, realm]() {
2019-05-30 12:14:20 +08:00
auto strongSelf = weakSelf.lock();
2020-07-10 10:42:23 +08:00
if (!strongSelf) {
2019-05-30 12:14:20 +08:00
//本对象已经销毁
return;
}
//base64忽略encrypted参数上层必须传入明文密码
2020-07-10 10:42:23 +08:00
if (pwd == good_pwd) {
2019-05-30 12:14:20 +08:00
//提供的密码且匹配正确
strongSelf->onAuthSuccess();
return;
}
//密码错误
2020-07-10 10:42:23 +08:00
strongSelf->onAuthFailed(realm, StrPrinter << "password mismatch when base64 auth:" << pwd << " != " << good_pwd);
2019-05-30 12:14:20 +08:00
});
2017-12-10 01:34:43 +08:00
};
2018-02-09 15:50:21 +08:00
2017-12-10 01:34:43 +08:00
//此时必须提供明文密码
2020-07-10 10:42:23 +08:00
if (!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth, _media_info, realm, user, true, invoker, static_cast<SockInfo &>(*this))) {
2017-12-10 01:34:43 +08:00
//表明该流需要认证却没监听请求密码事件,这一般是大意的程序所为,警告之
2019-05-30 12:14:20 +08:00
WarnP(this) << "请监听kBroadcastOnRtspAuth事件";
2017-12-10 01:34:43 +08:00
//但是我们还是忽略认证以便完成播放
//我们输入的密码是明文
2020-07-10 10:42:23 +08:00
invoker(false, pwd);
2017-12-10 01:34:43 +08:00
}
}
2020-07-10 10:42:23 +08:00
void RtspSession::onAuthDigest(const string &realm,const string &auth_md5){
DebugP(this) << auth_md5;
auto mapTmp = Parser::parseArgs(auth_md5, ",", "=");
2017-12-10 01:34:43 +08:00
decltype(mapTmp) map;
for(auto &pr : mapTmp){
map[trim(string(pr.first)," \"")] = trim(pr.second," \"");
2017-12-10 01:34:43 +08:00
}
//check realm
if(realm != map["realm"]){
2019-05-30 12:14:20 +08:00
onAuthFailed(realm,StrPrinter << "realm not mached:" << realm << " != " << map["realm"]);
2017-12-10 01:34:43 +08:00
return ;
}
//check nonce
auto nonce = map["nonce"];
2020-07-10 10:42:23 +08:00
if(_auth_nonce != nonce){
onAuthFailed(realm,StrPrinter << "nonce not mached:" << nonce << " != " << _auth_nonce);
2017-12-10 01:34:43 +08:00
return ;
}
//check username and uri
auto username = map["username"];
auto uri = map["uri"];
auto response = map["response"];
if(username.empty() || uri.empty() || response.empty()){
2019-05-30 12:14:20 +08:00
onAuthFailed(realm,StrPrinter << "username/uri/response empty:" << username << "," << uri << "," << response);
2017-12-10 01:34:43 +08:00
return ;
}
2019-05-30 12:14:20 +08:00
auto realInvoker = [this,realm,nonce,uri,username,response](bool ignoreAuth,bool encrypted,const string &good_pwd){
2017-12-10 01:34:43 +08:00
if(ignoreAuth){
//忽略认证
2019-05-30 12:14:20 +08:00
TraceP(this) << "auth ignored";
onAuthSuccess();
2017-12-10 01:34:43 +08:00
return;
}
/*
response计算方法如下
RTSP客户端应该使用username + password并计算response如下:
(1)password为MD5编码,
response = md5( password:nonce:md5(public_method:url) );
(2)password为ANSI字符串,
response= md5( md5(username:realm:password):nonce:md5(public_method:url) );
*/
auto encrypted_pwd = good_pwd;
if(!encrypted){
//提供的是明文密码
encrypted_pwd = MD5(username+ ":" + realm + ":" + good_pwd).hexdigest();
}
auto good_response = MD5( encrypted_pwd + ":" + nonce + ":" + MD5(string("DESCRIBE") + ":" + uri).hexdigest()).hexdigest();
2018-11-27 11:05:44 +08:00
if(strcasecmp(good_response.data(),response.data()) == 0){
2017-12-10 01:34:43 +08:00
//认证成功md5不区分大小写
2019-05-30 12:14:20 +08:00
onAuthSuccess();
2017-12-10 01:34:43 +08:00
}else{
//认证失败!
2019-05-30 12:14:20 +08:00
onAuthFailed(realm, StrPrinter << "password mismatch when md5 auth:" << good_response << " != " << response );
2017-12-10 01:34:43 +08:00
}
};
2019-05-30 12:14:20 +08:00
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
onAuth invoker = [realInvoker,weakSelf](bool encrypted,const string &good_pwd){
auto strongSelf = weakSelf.lock();
if(!strongSelf){
return;
}
//切换到自己的线程确保realInvoker执行时this指针有效
strongSelf->async([realInvoker,weakSelf,encrypted,good_pwd](){
auto strongSelf = weakSelf.lock();
if(!strongSelf){
return;
}
realInvoker(false,encrypted,good_pwd);
});
2017-12-10 01:34:43 +08:00
};
//此时可以提供明文或md5加密的密码
2020-07-10 10:42:23 +08:00
if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth, _media_info, realm, username, false, invoker, static_cast<SockInfo &>(*this))){
2017-12-10 01:34:43 +08:00
//表明该流需要认证却没监听请求密码事件,这一般是大意的程序所为,警告之
2019-05-30 12:14:20 +08:00
WarnP(this) << "请监听kBroadcastOnRtspAuth事件";
2017-12-10 01:34:43 +08:00
//但是我们还是忽略认证以便完成播放
realInvoker(true,true,"");
}
}
2019-05-30 12:14:20 +08:00
void RtspSession::onAuthUser(const string &realm,const string &authorization){
if(authorization.empty()){
onAuthFailed(realm,"", false);
return;
}
2017-12-10 01:34:43 +08:00
//请求中包含认证信息
auto authType = FindField(authorization.data(),NULL," ");
2020-03-20 11:51:24 +08:00
auto authStr = FindField(authorization.data()," ",NULL);
2017-12-10 01:34:43 +08:00
if(authType.empty() || authStr.empty()){
//认证信息格式不合法回复401 Unauthorized
2019-05-30 12:14:20 +08:00
onAuthFailed(realm,"can not find auth type or auth string");
2017-12-10 01:34:43 +08:00
return;
}
if(authType == "Basic"){
//base64认证需要明文密码
2019-05-30 12:14:20 +08:00
onAuthBasic(realm,authStr);
2017-12-10 01:34:43 +08:00
}else if(authType == "Digest"){
//md5认证
2019-05-30 12:14:20 +08:00
onAuthDigest(realm,authStr);
2017-12-10 01:34:43 +08:00
}else{
//其他认证方式?不支持!
2019-05-30 12:14:20 +08:00
onAuthFailed(realm,StrPrinter << "unsupported auth type:" << authType);
2017-12-10 01:34:43 +08:00
}
}
2020-07-10 10:42:23 +08:00
2021-01-31 19:18:17 +08:00
void RtspSession::send_StreamNotFound() {
2020-03-20 11:51:24 +08:00
sendRtspResponse("404 Stream Not Found",{"Connection","Close"});
2017-04-01 16:35:56 +08:00
}
2020-07-10 10:42:23 +08:00
2021-01-31 19:18:17 +08:00
void RtspSession::send_UnsupportedTransport() {
2020-03-20 11:51:24 +08:00
sendRtspResponse("461 Unsupported Transport",{"Connection","Close"});
2017-04-01 16:35:56 +08:00
}
2021-01-31 19:18:17 +08:00
void RtspSession::send_SessionNotFound() {
2020-03-20 11:51:24 +08:00
sendRtspResponse("454 Session Not Found",{"Connection","Close"});
2017-04-01 16:35:56 +08:00
}
2019-05-30 12:14:20 +08:00
void RtspSession::handleReq_Setup(const Parser &parser) {
2020-07-10 10:42:23 +08:00
//处理setup命令该函数可能进入多次
auto controlSuffix = split(parser.FullUrl(),"/").back();
2018-12-21 17:12:26 +08:00
if(controlSuffix.front() == '/'){
2020-03-20 11:51:24 +08:00
controlSuffix = controlSuffix.substr(1);
2018-12-21 17:12:26 +08:00
}
2020-03-20 11:51:24 +08:00
int trackIdx = getTrackIndexByControlSuffix(controlSuffix);
2020-07-10 10:42:23 +08:00
SdpTrack::Ptr &trackRef = _sdp_track[trackIdx];
2020-03-20 11:51:24 +08:00
if (trackRef->_inited) {
//已经初始化过该Track
2019-05-30 12:14:20 +08:00
throw SockException(Err_shutdown, "can not setup one track twice");
2020-03-20 11:51:24 +08:00
}
trackRef->_inited = true; //现在初始化
2020-07-10 10:42:23 +08:00
if(_rtp_type == Rtsp::RTP_Invalid){
2020-03-20 11:51:24 +08:00
auto &strTransport = parser["Transport"];
if(strTransport.find("TCP") != string::npos){
2020-07-10 10:42:23 +08:00
_rtp_type = Rtsp::RTP_TCP;
2020-03-20 11:51:24 +08:00
}else if(strTransport.find("multicast") != string::npos){
2020-07-10 10:42:23 +08:00
_rtp_type = Rtsp::RTP_MULTICAST;
2020-03-20 11:51:24 +08:00
}else{
2020-07-10 10:42:23 +08:00
_rtp_type = Rtsp::RTP_UDP;
2020-03-20 11:51:24 +08:00
}
}
2017-04-01 16:35:56 +08:00
//允许接收rtp、rtcp包
2020-07-10 10:42:23 +08:00
RtspSplitter::enableRecvRtp(_rtp_type == Rtsp::RTP_TCP);
2018-12-17 15:21:23 +08:00
2020-07-10 10:42:23 +08:00
switch (_rtp_type) {
2020-03-20 11:51:24 +08:00
case Rtsp::RTP_TCP: {
2020-07-10 10:42:23 +08:00
if(_push_src){
//rtsp推流时interleaved由推流者决定
auto key_values = Parser::parseArgs(parser["Transport"],";","=");
int interleaved_rtp = -1 , interleaved_rtcp = -1;
if(2 == sscanf(key_values["interleaved"].data(),"%d-%d",&interleaved_rtp,&interleaved_rtcp)){
trackRef->_interleaved = interleaved_rtp;
}else{
throw SockException(Err_shutdown, "can not find interleaved when setup of rtp over tcp");
}
}else{
//rtsp播放时由于数据共享分发所以interleaved必须由服务器决定
trackRef->_interleaved = 2 * trackRef->_type;
}
2020-03-20 11:51:24 +08:00
sendRtspResponse("200 OK",
2020-07-10 10:42:23 +08:00
{"Transport", StrPrinter << "RTP/AVP/TCP;unicast;"
<< "interleaved=" << (int) trackRef->_interleaved << "-"
<< (int) trackRef->_interleaved + 1 << ";"
<< "ssrc=" << printSSRC(trackRef->_ssrc),
"x-Transport-Options", "late-tolerance=1.400000",
"x-Dynamic-Rate", "1"
2020-03-20 11:51:24 +08:00
});
}
break;
2020-07-10 10:42:23 +08:00
2020-03-20 11:51:24 +08:00
case Rtsp::RTP_UDP: {
std::pair<Socket::Ptr, Socket::Ptr> pr = std::make_pair(createSocket(),createSocket());
try {
makeSockPair(pr, get_local_ip());
} catch (std::exception &ex) {
2020-03-20 11:51:24 +08:00
//分配端口失败
send_NotAcceptable();
2020-05-12 10:22:21 +08:00
throw SockException(Err_shutdown, ex.what());
2019-05-30 12:14:20 +08:00
}
2020-05-12 09:26:02 +08:00
2020-07-10 10:42:23 +08:00
_rtp_socks[trackIdx] = pr.first;
_rtcp_socks[trackIdx] = pr.second;
2020-05-12 09:26:02 +08:00
2020-03-20 11:51:24 +08:00
//设置客户端内网端口信息
string strClientPort = FindField(parser["Transport"].data(), "client_port=", NULL);
uint16_t ui16RtpPort = atoi(FindField(strClientPort.data(), NULL, "-").data());
uint16_t ui16RtcpPort = atoi(FindField(strClientPort.data(), "-", NULL).data());
2019-05-08 16:19:00 +08:00
struct sockaddr_in peerAddr;
//设置rtp发送目标地址
2020-03-20 11:51:24 +08:00
peerAddr.sin_family = AF_INET;
peerAddr.sin_port = htons(ui16RtpPort);
peerAddr.sin_addr.s_addr = inet_addr(get_peer_ip().data());
bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero);
pr.first->setSendPeerAddr((struct sockaddr *) (&peerAddr));
2019-05-08 16:19:00 +08:00
2020-03-20 11:51:24 +08:00
//设置rtcp发送目标地址
2019-05-08 16:19:00 +08:00
peerAddr.sin_family = AF_INET;
peerAddr.sin_port = htons(ui16RtcpPort);
peerAddr.sin_addr.s_addr = inet_addr(get_peer_ip().data());
bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero);
pr.second->setSendPeerAddr((struct sockaddr *) (&peerAddr));
2019-05-08 16:19:00 +08:00
2020-03-20 11:51:24 +08:00
//尝试获取客户端nat映射地址
startListenPeerUdpData(trackIdx);
//InfoP(this) << "分配端口:" << srv_port;
sendRtspResponse("200 OK",
2020-05-12 10:22:21 +08:00
{"Transport", StrPrinter << "RTP/AVP/UDP;unicast;"
<< "client_port=" << strClientPort << ";"
2020-07-10 10:42:23 +08:00
<< "server_port=" << pr.first->get_local_port() << "-"
<< pr.second->get_local_port() << ";"
2020-05-12 10:22:21 +08:00
<< "ssrc=" << printSSRC(trackRef->_ssrc)
2020-03-20 11:51:24 +08:00
});
}
break;
case Rtsp::RTP_MULTICAST: {
if(!_multicaster){
_multicaster = RtpMultiCaster::get(*this, get_local_ip(), _media_info._vhost, _media_info._app, _media_info._streamid);
2020-03-20 11:51:24 +08:00
if (!_multicaster) {
send_NotAcceptable();
2019-05-30 12:14:20 +08:00
throw SockException(Err_shutdown, "can not get a available udp multicast socket");
}
2020-03-20 11:51:24 +08:00
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
_multicaster->setDetachCB(this, [weakSelf]() {
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
}
strongSelf->safeShutdown(SockException(Err_shutdown,"ring buffer detached"));
});
}
int iSrvPort = _multicaster->getMultiCasterPort(trackRef->_type);
2020-03-20 11:51:24 +08:00
//我们用trackIdx区分rtp和rtcp包
//由于组播udp端口是共享的而rtcp端口为组播udp端口+1所以rtcp端口需要改成共享端口
auto pSockRtcp = UDPServer::Instance().getSock(*this, get_local_ip().data(), 2 * trackIdx + 1, iSrvPort + 1);
2020-03-20 11:51:24 +08:00
if (!pSockRtcp) {
//分配端口失败
send_NotAcceptable();
2019-05-30 12:14:20 +08:00
throw SockException(Err_shutdown, "open shared rtcp socket failed");
2020-03-20 11:51:24 +08:00
}
startListenPeerUdpData(trackIdx);
2019-05-28 17:14:36 +08:00
GET_CONFIG(uint32_t,udpTTL,MultiCast::kUdpTTL);
2020-03-20 11:51:24 +08:00
sendRtspResponse("200 OK",
2020-07-10 10:42:23 +08:00
{"Transport", StrPrinter << "RTP/AVP;multicast;"
<< "destination=" << _multicaster->getMultiCasterIP() << ";"
2020-07-10 10:42:23 +08:00
<< "source=" << get_local_ip() << ";"
<< "port=" << iSrvPort << "-" << pSockRtcp->get_local_port() << ";"
<< "ttl=" << udpTTL << ";"
<< "ssrc=" << printSSRC(trackRef->_ssrc)
2020-03-20 11:51:24 +08:00
});
}
break;
default:
break;
}
2017-04-01 16:35:56 +08:00
}
2019-05-30 12:14:20 +08:00
void RtspSession::handleReq_Play(const Parser &parser) {
2020-07-10 10:42:23 +08:00
if (_sdp_track.empty() || parser["Session"] != _sessionid) {
2020-03-20 11:51:24 +08:00
send_SessionNotFound();
2020-07-10 10:42:23 +08:00
throw SockException(Err_shutdown, _sdp_track.empty() ? "can not find any available track when play" : "session not found when play");
2019-05-30 12:14:20 +08:00
}
2020-07-10 10:42:23 +08:00
auto play_src = _play_src.lock();
if(!play_src){
2020-05-25 18:22:21 +08:00
send_StreamNotFound();
shutdown(SockException(Err_shutdown,"rtsp stream released"));
return;
}
2020-07-10 10:42:23 +08:00
bool useGOP = true;
_enable_send_rtp = false;
2020-05-25 18:22:21 +08:00
float iStartTime = 0;
2020-03-20 11:51:24 +08:00
auto strRange = parser["Range"];
2020-05-25 18:22:21 +08:00
if (strRange.size()) {
//这个是seek操作
auto strStart = FindField(strRange.data(), "npt=", "-");
if (strStart == "now") {
strStart = "0";
}
iStartTime = 1000 * (float)atof(strStart.data());
2020-05-25 18:22:21 +08:00
InfoP(this) << "rtsp seekTo(ms):" << iStartTime;
useGOP = !play_src->seekTo((uint32_t)iStartTime);
2020-07-10 10:42:23 +08:00
} else if (play_src->totalReaderCount() == 0) {
2020-05-25 18:22:21 +08:00
//第一个消费者
2020-07-10 10:42:23 +08:00
play_src->seekTo(0);
2020-05-25 18:22:21 +08:00
}
_StrPrinter rtp_info;
2020-07-10 10:42:23 +08:00
for (auto &track : _sdp_track) {
2020-05-25 18:22:21 +08:00
if (track->_inited == false) {
//还有track没有setup
shutdown(SockException(Err_shutdown, "track not setuped"));
2020-03-20 11:51:24 +08:00
return;
}
2020-07-10 10:42:23 +08:00
track->_ssrc = play_src->getSsrc(track->_type);
track->_seq = play_src->getSeqence(track->_type);
track->_time_stamp = play_src->getTimeStamp(track->_type);
2018-10-26 22:32:50 +08:00
2020-07-10 10:42:23 +08:00
rtp_info << "url=" << _content_base << "/" << track->_control_surffix << ";"
2020-05-25 18:22:21 +08:00
<< "seq=" << track->_seq << ";"
<< "rtptime=" << (int) (track->_time_stamp * (track->_samplerate / 1000)) << ",";
}
2020-05-25 18:22:21 +08:00
rtp_info.pop_back();
sendRtspResponse("200 OK",
2020-07-10 10:42:23 +08:00
{"Range", StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << (useGOP ? play_src->getTimeStamp(TrackInvalid) / 1000.0 : iStartTime / 1000),
2020-05-25 18:22:21 +08:00
"RTP-Info",rtp_info
});
2020-07-10 10:42:23 +08:00
_enable_send_rtp = true;
2020-05-25 18:22:21 +08:00
setSocketFlags();
2018-10-26 22:48:03 +08:00
2020-07-10 10:42:23 +08:00
if (!_play_reader && _rtp_type != Rtsp::RTP_MULTICAST) {
2020-05-25 18:22:21 +08:00
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
2020-07-10 10:42:23 +08:00
_play_reader = play_src->getRing()->attach(getPoller(), useGOP);
_play_reader->setDetachCB([weakSelf]() {
auto strongSelf = weakSelf.lock();
2020-05-25 18:22:21 +08:00
if (!strongSelf) {
return;
}
2020-05-25 18:22:21 +08:00
strongSelf->shutdown(SockException(Err_shutdown, "rtsp ring buffer detached"));
});
2020-07-10 10:42:23 +08:00
_play_reader->setReadCB([weakSelf](const RtspMediaSource::RingDataType &pack) {
2020-05-25 18:22:21 +08:00
auto strongSelf = weakSelf.lock();
if (!strongSelf) {
return;
}
2020-07-10 10:42:23 +08:00
if (strongSelf->_enable_send_rtp) {
2020-05-25 18:22:21 +08:00
strongSelf->sendRtpPacket(pack);
}
});
}
2017-04-01 16:35:56 +08:00
}
2019-05-30 12:14:20 +08:00
void RtspSession::handleReq_Pause(const Parser &parser) {
2020-07-10 10:42:23 +08:00
if (parser["Session"] != _sessionid) {
2020-03-20 11:51:24 +08:00
send_SessionNotFound();
2019-05-30 12:14:20 +08:00
throw SockException(Err_shutdown,"session not found when pause");
}
2020-03-20 11:51:24 +08:00
sendRtspResponse("200 OK");
2020-07-10 10:42:23 +08:00
_enable_send_rtp = false;
2017-04-01 16:35:56 +08:00
}
2019-05-30 12:14:20 +08:00
void RtspSession::handleReq_Teardown(const Parser &parser) {
2020-03-20 11:51:24 +08:00
sendRtspResponse("200 OK");
2019-05-30 12:14:20 +08:00
throw SockException(Err_shutdown,"rtsp player send teardown request");
2017-04-01 16:35:56 +08:00
}
2019-05-30 12:14:20 +08:00
void RtspSession::handleReq_Get(const Parser &parser) {
2020-03-20 11:51:24 +08:00
_http_x_sessioncookie = parser["x-sessioncookie"];
sendRtspResponse("200 OK",
{"Cache-Control","no-store",
"Pragma","no-store",
"Content-Type","application/x-rtsp-tunnelled",
},"","HTTP/1.0");
//注册http getter以便http poster绑定
lock_guard<recursive_mutex> lock(g_mtxGetter);
g_mapGetter[_http_x_sessioncookie] = dynamic_pointer_cast<RtspSession>(shared_from_this());
2017-04-01 16:35:56 +08:00
}
2019-05-30 12:14:20 +08:00
void RtspSession::handleReq_Post(const Parser &parser) {
2020-03-20 11:51:24 +08:00
lock_guard<recursive_mutex> lock(g_mtxGetter);
string sessioncookie = parser["x-sessioncookie"];
//Poster 找到 Getter
auto it = g_mapGetter.find(sessioncookie);
if (it == g_mapGetter.end()) {
2019-05-30 12:14:20 +08:00
throw SockException(Err_shutdown,"can not find http getter by x-sessioncookie");
}
2020-03-20 11:51:24 +08:00
//Poster 找到Getter的SOCK
auto httpGetterWeak = it->second;
//移除http getter的弱引用记录
g_mapGetter.erase(sessioncookie);
//http poster收到请求后转发给http getter处理
2020-07-10 10:42:23 +08:00
_on_recv = [this,httpGetterWeak](const Buffer::Ptr &buf){
2020-03-20 11:51:24 +08:00
auto httpGetterStrong = httpGetterWeak.lock();
if(!httpGetterStrong){
shutdown(SockException(Err_shutdown,"http getter released"));
return;
}
//切换到http getter的线程
2020-07-10 10:42:23 +08:00
httpGetterStrong->async([buf,httpGetterWeak](){
2020-03-20 11:51:24 +08:00
auto httpGetterStrong = httpGetterWeak.lock();
if(!httpGetterStrong){
return;
}
2020-07-10 10:42:23 +08:00
httpGetterStrong->onRecv(std::make_shared<BufferString>(decodeBase64(string(buf->data(), buf->size()))));
2020-03-20 11:51:24 +08:00
});
};
if(!parser.Content().empty()){
//http poster后面的粘包
2020-07-10 10:42:23 +08:00
_on_recv(std::make_shared<BufferString>(parser.Content()));
2020-03-20 11:51:24 +08:00
}
sendRtspResponse("200 OK",
{"Cache-Control","no-store",
"Pragma","no-store",
"Content-Type","application/x-rtsp-tunnelled",
},"","HTTP/1.0");
2017-04-01 16:35:56 +08:00
}
2019-05-30 12:14:20 +08:00
void RtspSession::handleReq_SET_PARAMETER(const Parser &parser) {
2020-03-20 11:51:24 +08:00
//TraceP(this) <<endl;
sendRtspResponse("200 OK");
2017-04-01 16:35:56 +08:00
}
2021-01-31 19:18:17 +08:00
void RtspSession::send_NotAcceptable() {
2020-03-20 11:51:24 +08:00
sendRtspResponse("406 Not Acceptable",{"Connection","Close"});
2017-04-01 16:35:56 +08:00
}
void RtspSession::onRtpSorted(const RtpPacket::Ptr &rtp, int track_idx) {
2020-07-10 10:42:23 +08:00
_push_src->onWrite(rtp, false);
2018-12-14 18:13:05 +08:00
}
2020-07-10 10:42:23 +08:00
2021-01-31 19:18:17 +08:00
void RtspSession::onRcvPeerUdpData(int interleaved, const Buffer::Ptr &buf, const struct sockaddr &addr) {
2020-03-20 11:51:24 +08:00
//这是rtcp心跳包说明播放器还存活
2020-07-10 10:42:23 +08:00
_alive_ticker.resetTime();
2020-03-20 11:51:24 +08:00
2020-07-10 10:42:23 +08:00
if (interleaved % 2 == 0) {
if (_push_src) {
2020-03-20 11:51:24 +08:00
//这是rtsp推流上来的rtp包
2020-07-10 10:42:23 +08:00
auto &ref = _sdp_track[interleaved / 2];
2021-01-31 19:18:17 +08:00
handleOneRtp(interleaved / 2, ref->_type, ref->_samplerate, (uint8_t *) buf->data(), buf->size());
2020-07-10 10:42:23 +08:00
} else if (!_udp_connected_flags.count(interleaved)) {
2019-06-27 12:53:35 +08:00
//这是rtsp播放器的rtp打洞包
2020-07-10 10:42:23 +08:00
_udp_connected_flags.emplace(interleaved);
_rtp_socks[interleaved / 2]->setSendPeerAddr(&addr);
2020-03-20 11:51:24 +08:00
}
2020-07-10 10:42:23 +08:00
} else {
2020-03-20 11:51:24 +08:00
//rtcp包
2020-07-10 10:42:23 +08:00
if (!_udp_connected_flags.count(interleaved)) {
_udp_connected_flags.emplace(interleaved);
_rtcp_socks[(interleaved - 1) / 2]->setSendPeerAddr(&addr);
2019-05-08 16:19:00 +08:00
}
onRtcpPacket((interleaved - 1) / 2, _sdp_track[(interleaved - 1) / 2], buf->data(), buf->size());
2019-05-08 14:23:18 +08:00
}
2017-04-01 16:35:56 +08:00
}
2021-01-31 19:18:17 +08:00
void RtspSession::startListenPeerUdpData(int track_idx) {
2020-03-20 11:51:24 +08:00
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
2019-05-08 16:24:45 +08:00
auto srcIP = inet_addr(get_peer_ip().data());
2020-07-10 10:42:23 +08:00
auto onUdpData = [weakSelf,srcIP](const Buffer::Ptr &buf, struct sockaddr *peer_addr, int interleaved){
auto strongSelf = weakSelf.lock();
if (!strongSelf) {
2020-03-20 11:51:24 +08:00
return false;
}
2019-05-28 18:46:52 +08:00
2020-07-10 10:42:23 +08:00
if (((struct sockaddr_in *) peer_addr)->sin_addr.s_addr != srcIP) {
WarnP(strongSelf.get()) << ((interleaved % 2 == 0) ? "收到其他地址的rtp数据:" : "收到其他地址的rtcp数据:")
<< SockUtil::inet_ntoa(((struct sockaddr_in *) peer_addr)->sin_addr);
2019-05-28 18:46:52 +08:00
return true;
}
2020-07-10 10:42:23 +08:00
struct sockaddr addr = *peer_addr;
strongSelf->async([weakSelf, buf, addr, interleaved]() {
auto strongSelf = weakSelf.lock();
if (!strongSelf) {
2020-03-20 11:51:24 +08:00
return;
}
2020-07-10 10:42:23 +08:00
strongSelf->onRcvPeerUdpData(interleaved, buf, addr);
2020-03-20 11:51:24 +08:00
});
return true;
};
2020-07-10 10:42:23 +08:00
switch (_rtp_type){
2020-03-20 11:51:24 +08:00
case Rtsp::RTP_MULTICAST:{
//组播使用的共享rtcp端口
2020-07-10 10:42:23 +08:00
UDPServer::Instance().listenPeer(get_peer_ip().data(), this,
[onUdpData]( int interleaved, const Buffer::Ptr &buf, struct sockaddr *peer_addr) {
return onUdpData(buf, peer_addr, interleaved);
2020-03-20 11:51:24 +08:00
});
}
break;
case Rtsp::RTP_UDP:{
2020-07-10 10:42:23 +08:00
auto setEvent = [&](Socket::Ptr &sock,int interleaved){
2020-03-20 11:51:24 +08:00
if(!sock){
2020-07-10 10:42:23 +08:00
WarnP(this) << "udp端口为空:" << interleaved;
2020-03-20 11:51:24 +08:00
return;
}
2020-07-10 10:42:23 +08:00
sock->setOnRead([onUdpData,interleaved](const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr , int addr_len){
onUdpData(pBuf, pPeerAddr, interleaved);
2020-03-20 11:51:24 +08:00
});
};
2020-07-10 10:42:23 +08:00
setEvent(_rtp_socks[track_idx], 2 * track_idx );
setEvent(_rtcp_socks[track_idx], 2 * track_idx + 1 );
2020-03-20 11:51:24 +08:00
}
break;
default:
break;
}
2017-04-01 16:35:56 +08:00
}
static string dateStr(){
2020-03-20 11:51:24 +08:00
char buf[64];
time_t tt = time(NULL);
strftime(buf, sizeof buf, "%a, %b %d %Y %H:%M:%S GMT", gmtime(&tt));
return buf;
}
2020-07-10 10:42:23 +08:00
bool RtspSession::sendRtspResponse(const string &res_code, const StrCaseMap &header_const, const string &sdp, const char *protocol){
2020-03-20 11:51:24 +08:00
auto header = header_const;
2020-07-10 10:42:23 +08:00
header.emplace("CSeq",StrPrinter << _cseq);
if(!_sessionid.empty()){
header.emplace("Session", _sessionid);
2020-03-20 11:51:24 +08:00
}
2020-04-04 19:55:11 +08:00
header.emplace("Server",SERVER_NAME);
2020-03-20 11:51:24 +08:00
header.emplace("Date",dateStr());
if(!sdp.empty()){
header.emplace("Content-Length",StrPrinter << sdp.size());
header.emplace("Content-Type","application/sdp");
}
_StrPrinter printer;
printer << protocol << " " << res_code << "\r\n";
for (auto &pr : header){
printer << pr.first << ": " << pr.second << "\r\n";
}
printer << "\r\n";
if(!sdp.empty()){
printer << sdp;
}
2019-05-28 18:46:52 +08:00
// DebugP(this) << printer;
return send(std::make_shared<BufferString>(std::move(printer))) > 0 ;
}
2021-01-19 16:05:38 +08:00
ssize_t RtspSession::send(Buffer::Ptr pkt){
2018-12-17 15:21:23 +08:00
// if(!_enableSendRtp){
2019-05-28 18:46:52 +08:00
// DebugP(this) << pkt->data();
2018-12-17 15:21:23 +08:00
// }
2020-07-10 10:42:23 +08:00
_bytes_usage += pkt->size();
return TcpSession::send(std::move(pkt));
}
2020-07-10 10:42:23 +08:00
bool RtspSession::sendRtspResponse(const string &res_code, const std::initializer_list<string> &header, const string &sdp, const char *protocol) {
2020-03-20 11:51:24 +08:00
string key;
StrCaseMap header_map;
int i = 0;
for(auto &val : header){
if(++i % 2 == 0){
header_map.emplace(key,val);
}else{
key = val;
}
}
return sendRtspResponse(res_code,header_map,sdp,protocol);
}
2021-01-31 19:18:17 +08:00
int RtspSession::getTrackIndexByTrackType(TrackType type) {
2020-07-10 10:42:23 +08:00
for (unsigned int i = 0; i < _sdp_track.size(); i++) {
if (type == _sdp_track[i]->_type) {
2020-03-20 11:51:24 +08:00
return i;
}
}
2020-07-10 10:42:23 +08:00
if(_sdp_track.size() == 1){
2019-11-25 17:59:04 +08:00
return 0;
}
2020-07-08 22:19:05 +08:00
throw SockException(Err_shutdown, StrPrinter << "no such track with type:" << (int) type);
}
2020-07-10 10:42:23 +08:00
2021-01-31 19:18:17 +08:00
int RtspSession::getTrackIndexByControlSuffix(const string &controlSuffix) {
2020-07-10 10:42:23 +08:00
for (unsigned int i = 0; i < _sdp_track.size(); i++) {
if (controlSuffix == _sdp_track[i]->_control_surffix) {
2020-03-20 11:51:24 +08:00
return i;
}
}
2020-07-10 10:42:23 +08:00
if(_sdp_track.size() == 1){
2018-12-21 17:12:26 +08:00
return 0;
2020-03-20 11:51:24 +08:00
}
2020-07-08 22:19:05 +08:00
throw SockException(Err_shutdown, StrPrinter << "no such track with suffix:" << controlSuffix);
}
2021-01-31 19:18:17 +08:00
int RtspSession::getTrackIndexByInterleaved(int interleaved){
2020-07-10 10:42:23 +08:00
for (unsigned int i = 0; i < _sdp_track.size(); i++) {
if (_sdp_track[i]->_interleaved == interleaved) {
2020-03-20 11:51:24 +08:00
return i;
}
}
2020-07-10 10:42:23 +08:00
if(_sdp_track.size() == 1){
2019-11-25 17:59:04 +08:00
return 0;
}
2020-07-08 22:19:05 +08:00
throw SockException(Err_shutdown, StrPrinter << "no such track with interleaved:" << interleaved);
2018-12-17 15:21:23 +08:00
}
2020-07-10 10:42:23 +08:00
bool RtspSession::close(MediaSource &sender, bool force) {
2019-05-31 15:40:55 +08:00
//此回调在其他线程触发
2020-07-10 10:42:23 +08:00
if(!_push_src || (!force && _push_src->totalReaderCount())){
2019-05-27 18:39:43 +08:00
return false;
}
2020-03-20 11:51:24 +08:00
string err = StrPrinter << "close media:" << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force;
safeShutdown(SockException(Err_shutdown,err));
return true;
}
2019-12-28 16:48:11 +08:00
int RtspSession::totalReaderCount(MediaSource &sender) {
2020-07-10 10:42:23 +08:00
return _push_src ? _push_src->totalReaderCount() : sender.readerCount();
}
2020-09-27 11:32:49 +08:00
MediaOriginType RtspSession::getOriginType(MediaSource &sender) const{
return MediaOriginType::rtsp_push;
}
string RtspSession::getOriginUrl(MediaSource &sender) const {
return _media_info._full_url;
}
std::shared_ptr<SockInfo> RtspSession::getOriginSock(MediaSource &sender) const {
return const_cast<RtspSession *>(this)->shared_from_this();
}
2021-01-31 19:18:17 +08:00
void RtspSession::onBeforeRtpSorted(const RtpPacket::Ptr &rtp, int track_index){
updateRtcpContext(rtp);
}
void RtspSession::updateRtcpContext(const RtpPacket::Ptr &rtp){
int track_index = getTrackIndexByTrackType(rtp->type);
auto &rtcp_ctx = _rtcp_context[track_index];
2021-01-31 19:19:24 +08:00
rtcp_ctx->onRtp(rtp->getSeq(), rtp->getStampMS(), rtp->size() - RtpPacket::kRtpTcpHeaderSize);
2021-01-31 19:18:17 +08:00
2020-07-10 10:42:23 +08:00
auto &ticker = _rtcp_send_tickers[track_index];
2021-01-31 19:18:17 +08:00
//send rtcp every 5 second
2020-07-10 10:42:23 +08:00
if (ticker.elapsedTime() > 5 * 1000) {
ticker.resetTime();
2021-01-31 19:18:17 +08:00
static auto send_rtcp = [](RtspSession *thiz, int index, Buffer::Ptr ptr) {
if (thiz->_rtp_type == Rtsp::RTP_TCP) {
auto &track = thiz->_sdp_track[index];
thiz->send(makeRtpOverTcpPrefix((uint16_t)(ptr->size()), track->_interleaved + 1));
thiz->send(std::move(ptr));
} else {
thiz->_rtcp_socks[index]->send(std::move(ptr));
}
};
2021-01-31 19:19:24 +08:00
auto ssrc = rtp->getSSRC();
auto rtcp = _push_src ? rtcp_ctx->createRtcpRR(ssrc + 1, ssrc) : rtcp_ctx->createRtcpSR(ssrc + 1);
2021-01-31 19:18:17 +08:00
auto rtcp_sdes = RtcpSdes::create({SERVER_NAME});
rtcp_sdes->items.type = (uint8_t)SdesType::RTCP_SDES_CNAME;
2021-01-31 19:19:24 +08:00
rtcp_sdes->items.ssrc = htonl(ssrc);
2021-01-31 19:18:17 +08:00
send_rtcp(this, track_index, std::move(rtcp));
send_rtcp(this, track_index, RtcpHeader::toBuffer(rtcp_sdes));
2020-07-10 10:42:23 +08:00
}
2019-12-28 16:48:11 +08:00
}
2019-05-31 15:40:55 +08:00
2020-04-07 13:03:53 +08:00
void RtspSession::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) {
2020-07-10 10:42:23 +08:00
switch (_rtp_type) {
2019-05-08 17:49:05 +08:00
case Rtsp::RTP_TCP: {
size_t i = 0;
auto size = pkt->size();
2020-04-07 13:03:53 +08:00
setSendFlushFlag(false);
pkt->for_each([&](const RtpPacket::Ptr &rtp) {
2021-01-31 19:18:17 +08:00
updateRtcpContext(rtp);
2020-04-07 13:03:53 +08:00
if (++i == size) {
setSendFlushFlag(true);
}
send(rtp);
});
2019-05-08 17:49:05 +08:00
}
break;
case Rtsp::RTP_UDP: {
size_t i = 0;
auto size = pkt->size();
2020-04-07 13:03:53 +08:00
pkt->for_each([&](const RtpPacket::Ptr &rtp) {
2021-01-31 19:18:17 +08:00
updateRtcpContext(rtp);
2020-07-10 10:42:23 +08:00
int track_index = getTrackIndexByTrackType(rtp->type);
auto &pSock = _rtp_socks[track_index];
2020-04-07 13:03:53 +08:00
if (!pSock) {
shutdown(SockException(Err_shutdown, "udp sock not opened yet"));
return;
}
2021-02-02 10:33:56 +08:00
_bytes_usage += rtp->size() - RtpPacket::kRtpTcpHeaderSize;
pSock->send(std::make_shared<BufferRtp>(rtp, RtpPacket::kRtpTcpHeaderSize), nullptr, 0, ++i == size);
2020-04-07 13:03:53 +08:00
});
2019-05-08 17:49:05 +08:00
}
break;
default:
break;
}
}
void RtspSession::setSocketFlags(){
2020-04-29 11:08:43 +08:00
GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS);
if(mergeWriteMS > 0) {
//推流模式下关闭TCP_NODELAY会增加推流端的延时但是服务器性能将提高
SockUtil::setNoDelay(getSock()->rawFD(), false);
//播放模式下开启MSG_MORE会增加延时但是能提高发送性能
2020-04-23 17:50:12 +08:00
setSendFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE);
}
}
2017-04-01 16:35:56 +08:00
}
2018-10-24 17:17:55 +08:00
/* namespace mediakit */