ZLMediaKit/src/Rtsp/RtspSession.cpp

1267 lines
39 KiB
C++
Raw Normal View History

2018-11-14 09:52:28 +08:00
/*
2017-09-27 16:20:30 +08:00
* MIT License
2017-04-01 16:35:56 +08:00
*
2017-09-27 16:20:30 +08:00
* Copyright (c) 2016 xiongziliang <771730766@qq.com>
*
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
*
* 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.
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-04-25 11:35:41 +08:00
#include "Util/mini.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"
2017-04-25 11:35:41 +08:00
#include "Util/onceToken.h"
2017-04-01 16:35:56 +08:00
#include "Util/TimeTicker.h"
#include "Util/NoticeCenter.h"
2017-04-25 11:35:41 +08:00
#include "Network/sockutil.h"
2017-04-01 16:35:56 +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
static int kSockFlags = SOCKET_DEFAULE_FLAGS | FLAG_MORE;
2018-12-20 10:42:51 +08:00
RtspSession::RtspSession(const Socket::Ptr &pSock) : TcpSession(pSock) {
//设置10秒发送缓存
pSock->setSendBufSecond(10);
//设置15秒发送超时时间
pSock->setSendTimeOutSecond(15);
2017-04-01 16:35:56 +08:00
2018-02-23 15:36:51 +08:00
DebugL << get_peer_ip();
2017-04-01 16:35:56 +08:00
}
RtspSession::~RtspSession() {
2018-02-23 15:36:51 +08:00
DebugL << get_peer_ip();
2017-04-01 16:35:56 +08:00
}
void RtspSession::onError(const SockException& err) {
TraceL << err.getErrCode() << " " << err.what();
if (_rtpType == PlayerBase::RTP_MULTICAST) {
2017-11-08 16:56:02 +08:00
//取消UDP端口监听
2018-02-23 15:36:51 +08:00
UDPServer::Instance().stopListenPeer(get_peer_ip().data(), this);
2017-04-01 16:35:56 +08:00
}
if (_http_x_sessioncookie.size() != 0) {
//移除http getter的弱引用记录
lock_guard<recursive_mutex> lock(g_mtxGetter);
g_mapGetter.erase(_http_x_sessioncookie);
2017-04-01 16:35:56 +08:00
}
//流量统计事件广播
2018-02-09 11:42:55 +08:00
GET_CONFIG_AND_REGISTER(uint32_t,iFlowThreshold,Broadcast::kFlowThreshold);
2018-10-24 15:43:52 +08:00
if(_ui64TotalBytes > iFlowThreshold * 1024){
2018-10-09 09:36:03 +08:00
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,
2018-10-24 15:43:52 +08:00
_mediaInfo,
_ui64TotalBytes,
_ticker.createdTime()/1000,
2018-10-09 09:36:03 +08:00
*this);
}
2017-04-01 16:35:56 +08:00
}
void RtspSession::onManager() {
2018-10-24 15:43:52 +08:00
if (_ticker.createdTime() > 15 * 1000) {
if (_strSession.size() == 0) {
2018-02-23 15:36:51 +08:00
WarnL << "非法链接:" << get_peer_ip();
2017-04-01 16:35:56 +08:00
shutdown();
return;
}
}
//组播不检查心跳是否超时
if (_rtpType == PlayerBase::RTP_UDP && _ticker.elapsedTime() > 15 * 1000) {
2018-02-23 15:36:51 +08:00
WarnL << "RTSP会话超时:" << get_peer_ip();
2017-04-01 16:35:56 +08:00
shutdown();
return;
}
if(_delayTask){
if(time(NULL) > _iTaskTimeLine){
_delayTask();
_delayTask = nullptr;
}
}
2017-04-01 16:35:56 +08:00
}
2018-12-17 15:21:23 +08:00
void RtspSession::onRecv(const Buffer::Ptr &pBuf) {
_ticker.resetTime();
_ui64TotalBytes += pBuf->size();
if (_onRecv) {
//http poster的请求数据转发给http getter处理
_onRecv(pBuf);
} else {
// TraceL << pBuf->size() << "\r\n" << pBuf->data();
input(pBuf->data(),pBuf->size());
}
}
2018-09-20 18:44:32 +08:00
2018-12-17 15:21:23 +08:00
void RtspSession::onWholeRtspPacket(Parser &parser) {
string strCmd = parser.Method(); //提取出请求命令字
_iCseq = atoi(parser["CSeq"].data());
2017-04-01 16:35:56 +08:00
2018-12-17 15:21:23 +08:00
typedef bool (RtspSession::*rtsp_request_handler)(const Parser &parser);
static unordered_map<string, rtsp_request_handler> s_handler_map;
static onceToken token( []() {
s_handler_map.emplace("OPTIONS",&RtspSession::handleReq_Options);
s_handler_map.emplace("DESCRIBE",&RtspSession::handleReq_Describe);
s_handler_map.emplace("ANNOUNCE",&RtspSession::handleReq_ANNOUNCE);
2018-12-17 15:21:23 +08:00
s_handler_map.emplace("RECORD",&RtspSession::handleReq_RECORD);
s_handler_map.emplace("SETUP",&RtspSession::handleReq_Setup);
s_handler_map.emplace("PLAY",&RtspSession::handleReq_Play);
s_handler_map.emplace("PAUSE",&RtspSession::handleReq_Pause);
s_handler_map.emplace("TEARDOWN",&RtspSession::handleReq_Teardown);
s_handler_map.emplace("GET",&RtspSession::handleReq_Get);
s_handler_map.emplace("POST",&RtspSession::handleReq_Post);
s_handler_map.emplace("SET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER);
s_handler_map.emplace("GET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER);
}, []() {});
auto it = s_handler_map.find(strCmd);
if (it != s_handler_map.end()) {
2018-12-17 15:21:23 +08:00
auto &fun = it->second;
if(!(this->*fun)(parser)){
shutdown();
2018-09-20 18:44:32 +08:00
}
} else{
2017-04-01 16:35:56 +08:00
shutdown();
WarnL << "不支持的rtsp命令:" << strCmd;
2017-04-01 16:35:56 +08:00
}
2018-09-20 18:44:32 +08:00
}
2018-12-17 15:21:23 +08:00
void RtspSession::onRtpPacket(const char *data, uint64_t len) {
2018-12-20 17:06:33 +08:00
if(!_pushSrc){
return;
}
2018-12-17 15:21:23 +08:00
if(len > 1600){
//没有大于MTU的包
return;
}
int trackIdx = -1;
uint8_t interleaved = data[1];
if(interleaved %2 == 0){
trackIdx = getTrackIndexByInterleaved(interleaved);
}
if (trackIdx != -1) {
handleOneRtp(trackIdx,_aTrackInfo[trackIdx],(unsigned char *)data + 4, len - 4);
2018-09-20 18:44:32 +08:00
}
}
2018-12-17 15:21:23 +08:00
int64_t RtspSession::getContentLength(Parser &parser) {
if(parser.Method() == "POST"){
//http post请求的content数据部分是base64编码后的rtsp请求信令包
return remainDataSize();
2018-09-20 18:44:32 +08:00
}
2018-12-17 15:21:23 +08:00
return RtspSplitter::getContentLength(parser);
2017-04-01 16:35:56 +08:00
}
2018-12-17 15:21:23 +08:00
bool RtspSession::handleReq_Options(const Parser &parser) {
//支持这些命令
sendRtspResponse("200 OK",{"Public" , "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, ANNOUNCE, RECORD, SET_PARAMETER, GET_PARAMETER"});
2018-12-17 15:21:23 +08:00
return true;
2017-04-01 16:35:56 +08:00
}
2018-12-17 15:21:23 +08:00
bool RtspSession::handleReq_ANNOUNCE(const Parser &parser) {
_strSdp = parser.Content();
//解析url获取媒体名称
_mediaInfo.parse(parser.FullUrl());
auto src = dynamic_pointer_cast<RtmpMediaSource>(MediaSource::find(RTSP_SCHEMA,
_mediaInfo._vhost,
_mediaInfo._app,
_mediaInfo._streamid,
false));
if(src){
sendRtspResponse("406 Not Acceptable", {"Content-Type", "text/plain"}, "Already publishing.");
WarnL << "ANNOUNCE:"
<< "Already publishing:"
<< _mediaInfo._vhost << " "
<< _mediaInfo._app << " "
<< _mediaInfo._streamid << endl;
return false;
}
2018-12-14 18:13:05 +08:00
2018-12-17 15:21:23 +08:00
_strSession = makeRandStr(12);
_aTrackInfo = SdpAttr(_strSdp).getAvailableTrack();
_strUrl = parser.Url();
2018-12-14 18:13:05 +08:00
2018-12-17 15:21:23 +08:00
_pushSrc = std::make_shared<RtspToRtmpMediaSource>(_mediaInfo._vhost,_mediaInfo._app,_mediaInfo._streamid);
_pushSrc->setListener(dynamic_pointer_cast<MediaSourceEvent>(shared_from_this()));
_pushSrc->onGetSDP(_strSdp);
sendRtspResponse("200 OK");
return true;
}
2018-12-17 15:21:23 +08:00
bool RtspSession::handleReq_RECORD(const Parser &parser){
if (_aTrackInfo.empty() || parser["Session"] != _strSession) {
send_SessionNotFound();
2018-12-17 15:21:23 +08:00
return false;
}
auto onRes = [this](const string &err){
bool authSuccess = err.empty();
if(!authSuccess){
//第一次play是播放否则是恢复播放。只对播放鉴权
sendRtspResponse("401 Unauthorized", {"Content-Type", "text/plain"}, err);
shutdown();
return;
}
_StrPrinter rtp_info;
for(auto &track : _aTrackInfo){
if (track->_inited == false) {
//还有track没有setup
shutdown();
return;
}
rtp_info << "url=" << _strUrl << "/" << track->_control_surffix << ",";
}
rtp_info.pop_back();
sendRtspResponse("200 OK", {"RTP-Info",rtp_info});
SockUtil::setNoDelay(_sock->rawFD(),false);
(*this) << SocketFlags(kSockFlags);
};
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
Broadcast::AuthInvoker invoker = [weakSelf,onRes](const string &err){
auto strongSelf = weakSelf.lock();
if(!strongSelf){
return;
}
strongSelf->async([weakSelf,onRes,err](){
auto strongSelf = weakSelf.lock();
if(!strongSelf){
return;
}
onRes(err);
});
};
//rtsp推流需要鉴权
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPublish,_mediaInfo,invoker,*this);
if(!flag){
//该事件无人监听,默认不鉴权
onRes("");
}
2018-12-17 15:21:23 +08:00
return true;
}
2018-12-17 15:21:23 +08:00
bool RtspSession::handleReq_Describe(const Parser &parser) {
//解析url获取媒体名称
_strUrl = parser.Url();
_mediaInfo.parse(parser.FullUrl());
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
auto authorization = parser["Authorization"];
2018-12-17 15:21:23 +08:00
findStream([weakSelf,authorization](bool success){
auto strongSelf = weakSelf.lock();
if(!strongSelf){
return;
}
2018-10-29 15:02:18 +08:00
if(!success){
//未找到相应的MediaSource
2018-10-31 12:11:14 +08:00
WarnL << "No such stream:" << strongSelf->_mediaInfo._vhost << " " << strongSelf->_mediaInfo._app << " " << strongSelf->_mediaInfo._streamid;
strongSelf->send_StreamNotFound();
strongSelf->shutdown();
return;
}
//该请求中的认证信息
onGetRealm invoker = [weakSelf,authorization](const string &realm){
if(realm.empty()){
//无需认证,回复sdp
onAuthSuccess(weakSelf);
return;
}
//该流需要认证
onAuthUser(weakSelf,realm,authorization);
};
//广播是否需要认证事件
if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnGetRtspRealm,
strongSelf->_mediaInfo,
invoker,
*strongSelf)){
//无人监听此事件,说明无需认证
invoker("");
}
});
2018-12-17 15:21:23 +08:00
return true;
2017-04-01 16:35:56 +08:00
}
2017-12-10 01:34:43 +08:00
void RtspSession::onAuthSuccess(const weak_ptr<RtspSession> &weakSelf) {
auto strongSelf = weakSelf.lock();
if(!strongSelf){
//本对象已销毁
return;
}
strongSelf->async([weakSelf](){
auto strongSelf = weakSelf.lock();
if(!strongSelf){
//本对象已销毁
return;
}
strongSelf->sendRtspResponse("200 OK",
{"Content-Base",strongSelf->_strUrl,
"x-Accept-Retransmit","our-retransmit",
"x-Accept-Dynamic-Rate","1"
},strongSelf->_strSdp);
2017-12-10 01:34:43 +08:00
});
}
void RtspSession::onAuthFailed(const weak_ptr<RtspSession> &weakSelf,const string &realm) {
auto strongSelf = weakSelf.lock();
if(!strongSelf){
//本对象已销毁
return;
}
strongSelf->async([weakSelf,realm]() {
auto strongSelf = weakSelf.lock();
if (!strongSelf) {
//本对象已销毁
return;
}
2017-04-01 16:35:56 +08:00
2018-10-24 17:17:55 +08:00
GET_CONFIG_AND_REGISTER(bool,authBasic,Rtsp::kAuthBasic);
2017-12-10 01:34:43 +08:00
if (!authBasic) {
//我们需要客户端优先以md5方式认证
strongSelf->_strNonce = makeRandStr(32);
strongSelf->sendRtspResponse("401 Unauthorized",
{"WWW-Authenticate",
StrPrinter << "Digest realm=\"" << realm << "\",nonce=\"" << strongSelf->_strNonce << "\"" },
strongSelf->_strSdp);
2017-12-10 01:34:43 +08:00
}else {
//当然我们也支持base64认证,但是我们不建议这样做
strongSelf->sendRtspResponse("401 Unauthorized",
{"WWW-Authenticate",
StrPrinter << "Basic realm=\"" << realm << "\"" },
strongSelf->_strSdp);
2017-12-10 01:34:43 +08:00
}
});
}
void RtspSession::onAuthBasic(const weak_ptr<RtspSession> &weakSelf,const string &realm,const string &strBase64){
//base64认证
char user_pwd_buf[512];
av_base64_decode((uint8_t *)user_pwd_buf,strBase64.data(),strBase64.size());
auto user_pwd_vec = split(user_pwd_buf,":");
2017-12-10 01:34:43 +08:00
if(user_pwd_vec.size() < 2){
//认证信息格式不合法回复401 Unauthorized
onAuthFailed(weakSelf,realm);
return;
}
auto user = user_pwd_vec[0];
auto pwd = user_pwd_vec[1];
onAuth invoker = [pwd,realm,weakSelf](bool encrypted,const string &good_pwd){
if(!encrypted && pwd == good_pwd){
//提供的是明文密码且匹配正确
onAuthSuccess(weakSelf);
}else{
//密码错误
onAuthFailed(weakSelf,realm);
}
};
2018-02-09 15:50:21 +08:00
auto strongSelf = weakSelf.lock();
if(!strongSelf){
//本对象已销毁
return;
}
2017-12-10 01:34:43 +08:00
//此时必须提供明文密码
2018-10-24 15:43:52 +08:00
if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth,strongSelf->_mediaInfo,user, true,invoker,*strongSelf)){
2017-12-10 01:34:43 +08:00
//表明该流需要认证却没监听请求密码事件,这一般是大意的程序所为,警告之
WarnL << "请监听kBroadcastOnRtspAuth事件";
//但是我们还是忽略认证以便完成播放
//我们输入的密码是明文
invoker(false,pwd);
}
}
2017-12-10 01:34:43 +08:00
void RtspSession::onAuthDigest(const weak_ptr<RtspSession> &weakSelf,const string &realm,const string &strMd5){
auto strongSelf = weakSelf.lock();
if(!strongSelf){
return;
}
DebugL << strMd5;
auto mapTmp = Parser::parseArgs(strMd5,",","=");
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"]){
TraceL << "realm not mached:" << realm << "," << map["realm"];
onAuthFailed(weakSelf,realm);
return ;
}
//check nonce
auto nonce = map["nonce"];
2018-10-24 15:43:52 +08:00
if(strongSelf->_strNonce != nonce){
TraceL << "nonce not mached:" << nonce << "," << strongSelf->_strNonce;
2017-12-10 01:34:43 +08:00
onAuthFailed(weakSelf,realm);
return ;
}
//check username and uri
auto username = map["username"];
auto uri = map["uri"];
auto response = map["response"];
if(username.empty() || uri.empty() || response.empty()){
TraceL << "username/uri/response empty:" << username << "," << uri << "," << response;
onAuthFailed(weakSelf,realm);
return ;
}
auto realInvoker = [weakSelf,realm,nonce,uri,username,response](bool ignoreAuth,bool encrypted,const string &good_pwd){
if(ignoreAuth){
//忽略认证
onAuthSuccess(weakSelf);
TraceL << "auth ignored";
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不区分大小写
onAuthSuccess(weakSelf);
TraceL << "onAuthSuccess";
}else{
//认证失败!
onAuthFailed(weakSelf,realm);
TraceL << "onAuthFailed";
}
};
onAuth invoker = [realInvoker](bool encrypted,const string &good_pwd){
realInvoker(false,encrypted,good_pwd);
};
//此时可以提供明文或md5加密的密码
2018-10-24 15:43:52 +08:00
if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth,strongSelf->_mediaInfo,username, false,invoker,*strongSelf)){
2017-12-10 01:34:43 +08:00
//表明该流需要认证却没监听请求密码事件,这一般是大意的程序所为,警告之
WarnL << "请监听kBroadcastOnRtspAuth事件";
//但是我们还是忽略认证以便完成播放
realInvoker(true,true,"");
}
}
void RtspSession::onAuthUser(const weak_ptr<RtspSession> &weakSelf,const string &realm,const string &authorization){
//请求中包含认证信息
auto authType = FindField(authorization.data(),NULL," ");
auto authStr = FindField(authorization.data()," ",NULL);
if(authType.empty() || authStr.empty()){
//认证信息格式不合法回复401 Unauthorized
onAuthFailed(weakSelf,realm);
return;
}
if(authType == "Basic"){
//base64认证需要明文密码
onAuthBasic(weakSelf,realm,authStr);
}else if(authType == "Digest"){
//md5认证
onAuthDigest(weakSelf,realm,authStr);
}else{
//其他认证方式?不支持!
onAuthFailed(weakSelf,realm);
}
}
2017-04-01 16:35:56 +08:00
inline void RtspSession::send_StreamNotFound() {
sendRtspResponse("404 Stream Not Found",{"Connection","Close"});
2017-04-01 16:35:56 +08:00
}
inline void RtspSession::send_UnsupportedTransport() {
sendRtspResponse("461 Unsupported Transport",{"Connection","Close"});
2017-04-01 16:35:56 +08:00
}
inline void RtspSession::send_SessionNotFound() {
sendRtspResponse("454 Session Not Found",{"Connection","Close"});
2017-04-01 16:35:56 +08:00
}
2018-12-17 15:21:23 +08:00
bool RtspSession::handleReq_Setup(const Parser &parser) {
2017-04-01 16:35:56 +08:00
//处理setup命令该函数可能进入多次
2018-12-17 15:21:23 +08:00
auto controlSuffix = parser.FullUrl().substr(1 + parser.FullUrl().rfind('/'));
2018-03-26 18:56:22 +08:00
int trackIdx = getTrackIndexByControlSuffix(controlSuffix);
2017-04-01 16:35:56 +08:00
if (trackIdx == -1) {
//未找到相应track
2018-12-17 15:21:23 +08:00
return false;
2017-04-01 16:35:56 +08:00
}
2018-10-26 09:56:29 +08:00
SdpTrack::Ptr &trackRef = _aTrackInfo[trackIdx];
2018-10-26 10:59:13 +08:00
if (trackRef->_inited) {
2017-04-01 16:35:56 +08:00
//已经初始化过该Track
2018-12-17 15:21:23 +08:00
return false;
2017-04-01 16:35:56 +08:00
}
2018-10-26 10:59:13 +08:00
trackRef->_inited = true; //现在初始化
2017-04-01 16:35:56 +08:00
if(_rtpType == PlayerBase::RTP_Invalid){
2018-12-17 15:21:23 +08:00
auto strTransport = parser["Transport"];
2017-04-01 16:35:56 +08:00
if(strTransport.find("TCP") != string::npos){
2018-10-24 15:43:52 +08:00
_rtpType = PlayerBase::RTP_TCP;
2017-04-01 16:35:56 +08:00
}else if(strTransport.find("multicast") != string::npos){
2018-10-24 15:43:52 +08:00
_rtpType = PlayerBase::RTP_MULTICAST;
2017-04-01 16:35:56 +08:00
}else{
2018-10-24 15:43:52 +08:00
_rtpType = PlayerBase::RTP_UDP;
2017-04-01 16:35:56 +08:00
}
}
2018-12-17 15:21:23 +08:00
//允许接收rtp、rtcp包
RtspSplitter::enableRecvRtp(_rtpType == PlayerBase::RTP_TCP);
2018-10-24 15:43:52 +08:00
switch (_rtpType) {
2017-04-01 16:35:56 +08:00
case PlayerBase::RTP_TCP: {
2018-12-17 15:21:23 +08:00
trackRef->_interleaved = trackRef->_type * 2;
sendRtspResponse("200 OK",
{"Transport",StrPrinter << "RTP/AVP/TCP;unicast;"
<< "interleaved=" << trackRef->_type * 2 << "-" << trackRef->_type * 2 + 1 << ";"
<< "ssrc=" << printSSRC(trackRef->_ssrc),
"x-Transport-Options" , "late-tolerance=1.400000",
"x-Dynamic-Rate" , "1"
});
2017-04-01 16:35:56 +08:00
}
break;
case PlayerBase::RTP_UDP: {
2017-11-08 16:56:02 +08:00
//我们用trackIdx区分rtp和rtcp包
auto pSockRtp = std::make_shared<Socket>(_sock->getPoller());
if (!pSockRtp->bindUdpSock(0,get_local_ip().data())) {
2017-11-08 16:56:02 +08:00
//分配端口失败
WarnL << "分配rtp端口失败";
send_NotAcceptable();
2018-12-17 15:21:23 +08:00
return false;
2017-11-08 16:56:02 +08:00
}
auto pSockRtcp = std::make_shared<Socket>(_sock->getPoller());
if (!pSockRtcp->bindUdpSock(pSockRtp->get_local_port() + 1,get_local_ip().data())) {
2017-04-01 16:35:56 +08:00
//分配端口失败
2017-11-08 16:56:02 +08:00
WarnL << "分配rtcp端口失败";
2017-04-01 16:35:56 +08:00
send_NotAcceptable();
2018-12-17 15:21:23 +08:00
return false;
2017-04-01 16:35:56 +08:00
}
_apRtpSock[trackIdx] = pSockRtp;
_apRtcpSock[trackIdx] = pSockRtcp;
2017-11-08 16:56:02 +08:00
//设置客户端内网端口信息
2018-12-17 15:21:23 +08:00
string strClientPort = FindField(parser["Transport"].data(), "client_port=", NULL);
2017-04-01 16:35:56 +08:00
uint16_t ui16PeerPort = atoi( FindField(strClientPort.data(), NULL, "-").data());
struct sockaddr_in peerAddr;
peerAddr.sin_family = AF_INET;
peerAddr.sin_port = htons(ui16PeerPort);
2018-02-23 15:36:51 +08:00
peerAddr.sin_addr.s_addr = inet_addr(get_peer_ip().data());
2017-04-01 16:35:56 +08:00
bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero);
_apPeerRtpPortAddr[trackIdx].reset((struct sockaddr *) (new struct sockaddr_in(peerAddr)));
2017-11-08 16:56:02 +08:00
//尝试获取客户端nat映射地址
startListenPeerUdpData(trackIdx);
2017-04-01 16:35:56 +08:00
//InfoL << "分配端口:" << srv_port;
sendRtspResponse("200 OK",
{"Transport",StrPrinter << "RTP/AVP/UDP;unicast;"
<< "client_port=" << strClientPort << ";"
<< "server_port=" << pSockRtp->get_local_port() << "-" << pSockRtcp->get_local_port() << ";"
<< "ssrc=" << printSSRC(trackRef->_ssrc)
});
2017-04-01 16:35:56 +08:00
}
break;
case PlayerBase::RTP_MULTICAST: {
2018-10-24 15:43:52 +08:00
if(!_pBrdcaster){
_pBrdcaster = RtpBroadCaster::get(get_local_ip(),_mediaInfo._vhost, _mediaInfo._app, _mediaInfo._streamid);
if (!_pBrdcaster) {
2017-04-01 16:35:56 +08:00
send_NotAcceptable();
2018-12-17 15:21:23 +08:00
return false;
2017-04-01 16:35:56 +08:00
}
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
2018-10-24 15:43:52 +08:00
_pBrdcaster->setDetachCB(this, [weakSelf]() {
2017-04-01 16:35:56 +08:00
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
}
strongSelf->safeShutdown();
});
}
2018-10-26 10:59:13 +08:00
int iSrvPort = _pBrdcaster->getPort(trackRef->_type);
2017-11-08 16:56:02 +08:00
//我们用trackIdx区分rtp和rtcp包
//由于组播udp端口是共享的而rtcp端口为组播udp端口+1所以rtcp端口需要改成共享端口
2018-02-23 15:36:51 +08:00
auto pSockRtcp = UDPServer::Instance().getSock(get_local_ip().data(),2*trackIdx + 1,iSrvPort + 1);
2017-11-08 16:56:02 +08:00
if (!pSockRtcp) {
//分配端口失败
WarnL << "分配rtcp端口失败";
send_NotAcceptable();
2018-12-17 15:21:23 +08:00
return false;
2017-11-08 16:56:02 +08:00
}
startListenPeerUdpData(trackIdx);
2018-02-09 11:42:55 +08:00
GET_CONFIG_AND_REGISTER(uint32_t,udpTTL,MultiCast::kUdpTTL);
sendRtspResponse("200 OK",
{"Transport",StrPrinter << "RTP/AVP;multicast;"
<< "destination=" << _pBrdcaster->getIP() << ";"
<< "source=" << get_local_ip() << ";"
<< "port=" << iSrvPort << "-" << pSockRtcp->get_local_port() << ";"
<< "ttl=" << udpTTL << ";"
<< "ssrc=" << printSSRC(trackRef->_ssrc)
});
2017-04-01 16:35:56 +08:00
}
break;
default:
break;
}
2018-12-17 15:21:23 +08:00
return true;
2017-04-01 16:35:56 +08:00
}
2018-12-17 15:21:23 +08:00
bool RtspSession::handleReq_Play(const Parser &parser) {
if (_aTrackInfo.empty() || parser["Session"] != _strSession) {
2017-04-01 16:35:56 +08:00
send_SessionNotFound();
2018-12-17 15:21:23 +08:00
return false;
2017-04-01 16:35:56 +08:00
}
2018-12-17 15:21:23 +08:00
auto strRange = parser["Range"];
2018-05-22 18:41:56 +08:00
auto onRes = [this,strRange](const string &err){
2018-02-06 16:17:37 +08:00
bool authSuccess = err.empty();
2018-10-26 22:48:03 +08:00
if(!authSuccess){
//第一次play是播放否则是恢复播放。只对播放鉴权
sendRtspResponse("401 Unauthorized", {"Content-Type", "text/plain"}, err);
shutdown();
return;
}
2017-04-01 16:35:56 +08:00
2018-10-24 15:43:52 +08:00
auto pMediaSrc = _pMediaSrc.lock();
2018-10-26 22:32:50 +08:00
if(!pMediaSrc){
send_StreamNotFound();
shutdown();
return;
}
2018-10-26 22:32:50 +08:00
bool useBuf = true;
_enableSendRtp = false;
2018-10-26 22:32:50 +08:00
if (strRange.size() && !_bFirstPlay) {
2018-10-26 22:48:03 +08:00
//这个是seek操作
2018-10-26 22:32:50 +08:00
auto strStart = FindField(strRange.data(), "npt=", "-");
if (strStart == "now") {
strStart = "0";
}
auto iStartTime = 1000 * atof(strStart.data());
InfoL << "rtsp seekTo(ms):" << iStartTime;
useBuf = !pMediaSrc->seekTo(iStartTime);
}else if(pMediaSrc->getRing()->readerCount() == 0){
2018-10-26 22:32:50 +08:00
//第一个消费者
pMediaSrc->seekTo(0);
}
_bFirstPlay = false;
_StrPrinter rtp_info;
2018-10-26 10:12:37 +08:00
for(auto &track : _aTrackInfo){
2018-10-26 10:59:13 +08:00
if (track->_inited == false) {
2018-10-26 10:12:37 +08:00
//还有track没有setup
shutdown();
return;
}
2018-10-26 22:32:50 +08:00
track->_ssrc = pMediaSrc->getSsrc(track->_type);
track->_seq = pMediaSrc->getSeqence(track->_type);
track->_time_stamp = pMediaSrc->getTimeStamp(track->_type);
rtp_info << "url=" << _strUrl << "/" << track->_control_surffix << ";"
<< "seq=" << track->_seq << ";"
<< "rtptime=" << (int)(track->_time_stamp * (track->_samplerate / 1000)) << ",";
2018-10-26 10:12:37 +08:00
}
rtp_info.pop_back();
sendRtspResponse("200 OK",
{"Range", StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << pMediaSrc->getTimeStamp(TrackInvalid) / 1000.0,
"RTP-Info",rtp_info
});
_enableSendRtp = true;
//提高发送性能
(*this) << SocketFlags(kSockFlags);
SockUtil::setNoDelay(_sock->rawFD(),false);
(*this) << SocketFlags(kSockFlags);
2018-10-26 22:48:03 +08:00
if (!_pRtpReader && _rtpType != PlayerBase::RTP_MULTICAST) {
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
_pRtpReader = pMediaSrc->getRing()->attach(useBuf);
_pRtpReader->setDetachCB([weakSelf]() {
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
}
strongSelf->safeShutdown();
});
_pRtpReader->setReadCB([weakSelf](const RtpPacket::Ptr &pack) {
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
}
strongSelf->async([weakSelf,pack](){
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
}
if(strongSelf->_enableSendRtp) {
strongSelf->sendRtpPacket(pack);
}
});
});
}
};
2017-04-01 16:35:56 +08:00
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
2018-02-06 16:17:37 +08:00
Broadcast::AuthInvoker invoker = [weakSelf,onRes](const string &err){
auto strongSelf = weakSelf.lock();
if(!strongSelf){
return;
2017-04-01 16:35:56 +08:00
}
2018-02-06 16:17:37 +08:00
strongSelf->async([weakSelf,onRes,err](){
auto strongSelf = weakSelf.lock();
if(!strongSelf){
return;
}
2018-02-06 16:17:37 +08:00
onRes(err);
});
};
2018-10-26 22:48:03 +08:00
if(_bFirstPlay){
//第一次收到play命令需要鉴权
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,_mediaInfo,invoker,*this);
if(!flag){
//该事件无人监听,默认不鉴权
onRes("");
}
}else{
//后面是seek或恢复命令不需要鉴权
2018-02-06 16:17:37 +08:00
onRes("");
}
2018-12-17 15:21:23 +08:00
return true;
2017-04-01 16:35:56 +08:00
}
2018-12-17 15:21:23 +08:00
bool RtspSession::handleReq_Pause(const Parser &parser) {
if (parser["Session"] != _strSession) {
2017-04-01 16:35:56 +08:00
send_SessionNotFound();
2018-12-17 15:21:23 +08:00
return false;
2017-04-01 16:35:56 +08:00
}
sendRtspResponse("200 OK");
_enableSendRtp = false;
2018-12-17 15:21:23 +08:00
return true;
2017-04-01 16:35:56 +08:00
}
2018-12-17 15:21:23 +08:00
bool RtspSession::handleReq_Teardown(const Parser &parser) {
sendRtspResponse("200 OK");
2017-04-01 16:35:56 +08:00
TraceL << "播放器断开连接!";
2018-12-17 15:21:23 +08:00
return true;
2017-04-01 16:35:56 +08:00
}
2018-12-17 15:21:23 +08:00
bool RtspSession::handleReq_Get(const Parser &parser) {
_http_x_sessioncookie = parser["x-sessioncookie"];
sendRtspResponse("200 OK",
{"Connection","Close",
"Cache-Control","no-store",
"Pragma","no-store",
"Content-Type","application/x-rtsp-tunnelled",
},"","HTTP/1.0");
//注册http getter以便http poster绑定
2017-04-01 16:35:56 +08:00
lock_guard<recursive_mutex> lock(g_mtxGetter);
g_mapGetter[_http_x_sessioncookie] = dynamic_pointer_cast<RtspSession>(shared_from_this());
2018-12-17 15:21:23 +08:00
return true;
2017-04-01 16:35:56 +08:00
}
2018-12-17 15:21:23 +08:00
bool RtspSession::handleReq_Post(const Parser &parser) {
2017-04-01 16:35:56 +08:00
lock_guard<recursive_mutex> lock(g_mtxGetter);
2018-12-17 15:21:23 +08:00
string sessioncookie = parser["x-sessioncookie"];
//Poster 找到 Getter
2017-04-01 16:35:56 +08:00
auto it = g_mapGetter.find(sessioncookie);
if (it == g_mapGetter.end()) {
WarnL << "Http Poster未找到Http Getter";
2018-12-17 15:21:23 +08:00
return false;
2017-04-01 16:35:56 +08:00
}
//Poster 找到Getter的SOCK
auto httpGetterWeak = it->second;
//移除http getter的弱引用记录
2017-04-01 16:35:56 +08:00
g_mapGetter.erase(sessioncookie);
//http poster收到请求后转发给http getter处理
_onRecv = [this,httpGetterWeak](const Buffer::Ptr &pBuf){
auto httpGetterStrong = httpGetterWeak.lock();
if(!httpGetterStrong){
WarnL << "Http Getter已经释放";
shutdown();
return;
}
//切换到http getter的线程
httpGetterStrong->async([pBuf,httpGetterWeak](){
auto httpGetterStrong = httpGetterWeak.lock();
if(!httpGetterStrong){
return;
}
httpGetterStrong->onRecv(std::make_shared<BufferString>(decodeBase64(string(pBuf->data(),pBuf->size()))));
});
};
2018-12-17 15:21:23 +08:00
if(!parser.Content().empty()){
//http poster后面的粘包
_onRecv(std::make_shared<BufferString>(parser.Content()));
}
return true;
2017-04-01 16:35:56 +08:00
}
2018-12-17 15:21:23 +08:00
bool RtspSession::handleReq_SET_PARAMETER(const Parser &parser) {
2017-04-01 16:35:56 +08:00
//TraceL<<endl;
sendRtspResponse("200 OK");
2018-12-17 15:21:23 +08:00
return true;
2017-04-01 16:35:56 +08:00
}
inline void RtspSession::send_NotAcceptable() {
sendRtspResponse("406 Not Acceptable",{"Connection","Close"});
2017-04-01 16:35:56 +08:00
}
void RtspSession::doDelay(int delaySec, const std::function<void()> &fun) {
if(_delayTask){
_delayTask();
}
_delayTask = fun;
_iTaskTimeLine = time(NULL) + delaySec;
}
void RtspSession::cancelDelyaTask(){
_delayTask = nullptr;
}
void RtspSession::findStream(const function<void(bool)> &cb) {
bool success = findStream();
if (success) {
cb(true);
return;
}
2018-10-31 12:11:14 +08:00
//广播未找到流
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastNotFoundStream,_mediaInfo,*this);
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
auto task_id = this;
auto media_info = _mediaInfo;
auto onRegist = [task_id, weakSelf, media_info, cb](BroadcastMediaChangedArgs) {
if (bRegist &&
schema == media_info._schema &&
vhost == media_info._vhost &&
app == media_info._app &&
stream == media_info._streamid) {
2018-10-31 12:11:14 +08:00
//播发器请求的rtsp流终于注册上了
auto strongSelf = weakSelf.lock();
if (!strongSelf) {
return;
}
//切换到自己的线程再回复
//如果触发 kBroadcastMediaChanged 事件的线程与本RtspSession绑定的线程相同,
//那么strongSelf->async操作可能是同步操作,
//通过指定参数may_sync为false确保 NoticeCenter::delListener操作延后执行,
//以便防止遍历事件监听对象map时做删除操作
strongSelf->async([task_id, weakSelf, media_info, cb]() {
auto strongSelf = weakSelf.lock();
if (!strongSelf) {
return;
}
DebugL << "收到rtsp注册事件,回复播放器:" << media_info._schema << "/" << media_info._vhost << "/"
<< media_info._app << "/" << media_info._streamid;
cb(strongSelf->findStream());
//取消延时任务,防止多次回复
strongSelf->cancelDelyaTask();
//取消事件监听
//在事件触发时不能在当前线程移除事件监听,否则会导致遍历map时做删除操作导致程序崩溃
NoticeCenter::Instance().delListener(task_id, Broadcast::kBroadcastMediaChanged);
}, false);
}
};
NoticeCenter::Instance().addListener(task_id, Broadcast::kBroadcastMediaChanged, onRegist);
//5秒后执行失败回调
2018-10-31 11:05:26 +08:00
doDelay(5, [cb,task_id]() {
2018-10-31 11:04:01 +08:00
NoticeCenter::Instance().delListener(task_id,Broadcast::kBroadcastMediaChanged);
cb(false);
});
}
2017-04-01 16:35:56 +08:00
inline bool RtspSession::findStream() {
RtspMediaSource::Ptr pMediaSrc =
2018-10-24 15:43:52 +08:00
dynamic_pointer_cast<RtspMediaSource>( MediaSource::find(RTSP_SCHEMA,_mediaInfo._vhost, _mediaInfo._app,_mediaInfo._streamid) );
2017-04-01 16:35:56 +08:00
if (!pMediaSrc) {
return false;
}
2018-10-24 15:43:52 +08:00
_strSdp = pMediaSrc->getSdp();
SdpAttr sdpAttr(_strSdp);
_aTrackInfo = sdpAttr.getAvailableTrack();
2018-10-26 09:56:29 +08:00
2018-10-26 10:12:37 +08:00
if (_aTrackInfo.empty()) {
2017-04-01 16:35:56 +08:00
return false;
}
2018-10-24 15:43:52 +08:00
_strSession = makeRandStr(12);
_pMediaSrc = pMediaSrc;
2017-04-01 16:35:56 +08:00
2018-10-26 10:12:37 +08:00
for(auto &track : _aTrackInfo){
2018-10-26 10:59:13 +08:00
track->_ssrc = pMediaSrc->getSsrc(track->_type);
track->_seq = pMediaSrc->getSeqence(track->_type);
2018-10-26 14:12:16 +08:00
track->_time_stamp = pMediaSrc->getTimeStamp(track->_type);
2017-04-01 16:35:56 +08:00
}
return true;
}
2018-01-30 09:35:54 +08:00
inline void RtspSession::sendRtpPacket(const RtpPacket::Ptr & pkt) {
2017-04-01 16:35:56 +08:00
//InfoL<<(int)pkt.Interleaved;
2018-10-24 15:43:52 +08:00
switch (_rtpType) {
2017-04-01 16:35:56 +08:00
case PlayerBase::RTP_TCP: {
2018-01-30 09:35:54 +08:00
BufferRtp::Ptr buffer(new BufferRtp(pkt));
send(buffer);
2017-04-01 16:35:56 +08:00
#ifdef RTSP_SEND_RTCP
int iTrackIndex = getTrackIndexByTrackId(pkt.interleaved / 2);
2018-10-24 15:43:52 +08:00
RtcpCounter &counter = _aRtcpCnt[iTrackIndex];
2017-04-01 16:35:56 +08:00
counter.pktCnt += 1;
counter.octCount += (pkt.length - 12);
2018-10-24 15:43:52 +08:00
auto &_ticker = _aRtcpTicker[iTrackIndex];
if (_ticker.elapsedTime() > 5 * 1000) {
2017-04-01 16:35:56 +08:00
//send rtcp every 5 second
2018-10-24 15:43:52 +08:00
_ticker.resetTime();
2017-04-01 16:35:56 +08:00
counter.timeStamp = pkt.timeStamp;
sendRTCP();
}
#endif
}
break;
case PlayerBase::RTP_UDP: {
2018-07-05 18:48:08 +08:00
int iTrackIndex = getTrackIndexByTrackType(pkt->type);
auto &pSock = _apRtpSock[iTrackIndex];
2017-04-01 16:35:56 +08:00
if (!pSock) {
shutdown();
return;
}
auto &peerAddr = _apPeerRtpPortAddr[iTrackIndex];
2017-04-01 16:35:56 +08:00
if (!peerAddr) {
return;
}
2018-01-30 09:35:54 +08:00
BufferRtp::Ptr buffer(new BufferRtp(pkt,4));
2018-10-24 15:43:52 +08:00
_ui64TotalBytes += buffer->size();
2018-12-20 16:59:54 +08:00
pSock->send(buffer,SOCKET_DEFAULE_FLAGS, peerAddr.get());
2017-04-01 16:35:56 +08:00
}
break;
default:
break;
}
}
2018-12-14 18:13:05 +08:00
void RtspSession::onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx) {
2018-12-20 17:06:33 +08:00
_pushSrc->onWrite(rtppt, false);
2018-12-14 18:13:05 +08:00
}
2018-02-23 15:36:51 +08:00
inline void RtspSession::onRcvPeerUdpData(int iTrackIdx, const Buffer::Ptr &pBuf, const struct sockaddr& addr) {
//这是rtcp心跳包说明播放器还存活
_ticker.resetTime();
2017-11-08 16:56:02 +08:00
if(iTrackIdx % 2 == 0){
2018-12-20 17:06:33 +08:00
if(_pushSrc){
handleOneRtp(iTrackIdx / 2,_aTrackInfo[iTrackIdx / 2],( unsigned char *)pBuf->data(),pBuf->size());
}
2018-12-14 18:13:05 +08:00
2017-11-08 16:56:02 +08:00
//这是rtp探测包
2018-10-24 15:43:52 +08:00
if(!_bGotAllPeerUdp){
2017-11-08 16:56:02 +08:00
//还没有获取完整的rtp探测包
2018-02-23 15:36:51 +08:00
if(SockUtil::in_same_lan(get_local_ip().data(),get_peer_ip().data())){
2017-11-08 16:56:02 +08:00
//在内网中客户端上报的端口号是真实的所以我们忽略udp打洞包
2018-10-24 15:43:52 +08:00
_bGotAllPeerUdp = true;
2017-11-08 16:56:02 +08:00
return;
}
//设置真实的客户端nat映射端口号
_apPeerRtpPortAddr[iTrackIdx / 2].reset(new struct sockaddr(addr));
2018-10-24 15:43:52 +08:00
_abGotPeerUdp[iTrackIdx / 2] = true;
_bGotAllPeerUdp = true;//先假设获取到完整的rtp探测包
2018-10-26 10:12:37 +08:00
for (unsigned int i = 0; i < _aTrackInfo.size(); i++) {
2018-10-24 15:43:52 +08:00
if (!_abGotPeerUdp[i]) {
2017-11-08 16:56:02 +08:00
//还有track没获取到rtp探测包
2018-10-24 15:43:52 +08:00
_bGotAllPeerUdp = false;
2017-11-08 16:56:02 +08:00
break;
}
}
2017-04-01 16:35:56 +08:00
}
}
}
inline void RtspSession::startListenPeerUdpData(int trackIdx) {
2017-04-01 16:35:56 +08:00
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
auto onUdpData = [weakSelf](const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr,int iTrackIdx){
auto strongSelf=weakSelf.lock();
if(!strongSelf) {
return false;
}
struct sockaddr addr=*pPeerAddr;
2018-12-17 09:24:39 +08:00
strongSelf->async([weakSelf,pBuf,addr,iTrackIdx]() {
auto strongSelf=weakSelf.lock();
if(!strongSelf) {
return;
}
strongSelf->onRcvPeerUdpData(iTrackIdx,pBuf,addr);
});
return true;
};
switch (_rtpType){
case PlayerBase::RTP_MULTICAST:{
//组播使用的共享rtcp端口
UDPServer::Instance().listenPeer(get_peer_ip().data(), this, [onUdpData](
int iTrackIdx, const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr) {
return onUdpData(pBuf,pPeerAddr,iTrackIdx);
2017-04-01 16:35:56 +08:00
});
}
break;
case PlayerBase::RTP_UDP:{
auto setEvent = [&](Socket::Ptr &sock,int iTrackIdx){
if(!sock){
WarnL << "udp端口为空:" << iTrackIdx;
return;
}
sock->setOnRead([onUdpData,iTrackIdx](const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr){
onUdpData(pBuf,pPeerAddr,iTrackIdx);
});
};
setEvent(_apRtpSock[trackIdx], 2*trackIdx );
setEvent(_apRtcpSock[trackIdx], 2*trackIdx + 1 );
}
break;
default:
break;
}
2017-04-01 16:35:56 +08:00
}
static string dateStr(){
char buf[64];
time_t tt = time(NULL);
strftime(buf, sizeof buf, "%a, %b %d %Y %H:%M:%S GMT", gmtime(&tt));
return buf;
}
bool RtspSession::sendRtspResponse(const string &res_code,
const StrCaseMap &header_const,
const string &sdp,
const char *protocol){
auto header = header_const;
header.emplace("CSeq",StrPrinter << _iCseq);
if(!_strSession.empty()){
header.emplace("Session",_strSession);
}
header.emplace("Server",SERVER_NAME "(build in " __DATE__ " " __TIME__ ")");
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;
}
// DebugL << printer;
return send(std::make_shared<BufferString>(printer)) > 0 ;
}
int RtspSession::send(const Buffer::Ptr &pkt){
2018-12-17 15:21:23 +08:00
// if(!_enableSendRtp){
// DebugL << pkt->data();
// }
_ui64TotalBytes += pkt->size();
return TcpSession::send(pkt);
}
bool RtspSession::sendRtspResponse(const string &res_code,
const std::initializer_list<string> &header,
const string &sdp,
const char *protocol) {
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);
}
inline string RtspSession::printSSRC(uint32_t ui32Ssrc) {
char tmp[9] = { 0 };
ui32Ssrc = htonl(ui32Ssrc);
uint8_t *pSsrc = (uint8_t *) &ui32Ssrc;
for (int i = 0; i < 4; i++) {
sprintf(tmp + 2 * i, "%02X", pSsrc[i]);
}
return tmp;
}
inline int RtspSession::getTrackIndexByTrackType(TrackType type) {
for (unsigned int i = 0; i < _aTrackInfo.size(); i++) {
if (type == _aTrackInfo[i]->_type) {
return i;
}
}
return -1;
}
inline int RtspSession::getTrackIndexByControlSuffix(const string &controlSuffix) {
for (unsigned int i = 0; i < _aTrackInfo.size(); i++) {
if (controlSuffix == _aTrackInfo[i]->_control_surffix) {
return i;
}
}
return -1;
}
2018-12-17 15:21:23 +08:00
inline int RtspSession::getTrackIndexByInterleaved(int interleaved){
for (unsigned int i = 0; i < _aTrackInfo.size(); i++) {
if (_aTrackInfo[i]->_interleaved == interleaved) {
return i;
}
}
return -1;
}
bool RtspSession::close() {
InfoL << "kick out:" << _mediaInfo._vhost << " " << _mediaInfo._app << " " << _mediaInfo._streamid;
safeShutdown();
return true;
}
2017-04-01 16:35:56 +08:00
#ifdef RTSP_SEND_RTCP
inline void RtspSession::sendRTCP() {
//DebugL;
uint8_t aui8Rtcp[60] = {0};
uint8_t *pui8Rtcp_SR = aui8Rtcp + 4, *pui8Rtcp_SDES = pui8Rtcp_SR + 28;
2018-10-24 15:43:52 +08:00
for (uint8_t i = 0; i < _uiTrackCnt; i++) {
auto &track = _aTrackInfo[i];
auto &counter = _aRtcpCnt[i];
2017-04-01 16:35:56 +08:00
aui8Rtcp[0] = '$';
aui8Rtcp[1] = track.trackId * 2 + 1;
aui8Rtcp[2] = 56 / 256;
aui8Rtcp[3] = 56 % 256;
pui8Rtcp_SR[0] = 0x80;
pui8Rtcp_SR[1] = 0xC8;
pui8Rtcp_SR[2] = 0x00;
pui8Rtcp_SR[3] = 0x06;
uint32_t ssrc=htonl(track.ssrc);
memcpy(&pui8Rtcp_SR[4], &ssrc, 4);
uint64_t msw;
uint64_t lsw;
struct timeval tv;
gettimeofday(&tv, NULL);
msw = tv.tv_sec + 0x83AA7E80; /* 0x83AA7E80 is the number of seconds from 1900 to 1970 */
lsw = (uint32_t) ((double) tv.tv_usec * (double) (((uint64_t) 1) << 32) * 1.0e-6);
msw = htonl(msw);
memcpy(&pui8Rtcp_SR[8], &msw, 4);
lsw = htonl(lsw);
memcpy(&pui8Rtcp_SR[12], &lsw, 4);
uint32_t rtpStamp = htonl(counter.timeStamp);
memcpy(&pui8Rtcp_SR[16], &rtpStamp, 4);
uint32_t pktCnt = htonl(counter.pktCnt);
memcpy(&pui8Rtcp_SR[20], &pktCnt, 4);
uint32_t octCount = htonl(counter.octCount);
memcpy(&pui8Rtcp_SR[24], &octCount, 4);
pui8Rtcp_SDES[0] = 0x81;
pui8Rtcp_SDES[1] = 0xCA;
pui8Rtcp_SDES[2] = 0x00;
pui8Rtcp_SDES[3] = 0x06;
memcpy(&pui8Rtcp_SDES[4], &ssrc, 4);
pui8Rtcp_SDES[8] = 0x01;
pui8Rtcp_SDES[9] = 0x0f;
memcpy(&pui8Rtcp_SDES[10], "_ZL_RtspServer_", 15);
pui8Rtcp_SDES[25] = 0x00;
send((char *) aui8Rtcp, 60);
}
}
#endif
}
2018-10-24 17:17:55 +08:00
/* namespace mediakit */
2017-04-01 16:35:56 +08:00