RtspSession.cpp 34.5 KB
Newer Older
xiongziliang committed
1
/*
xiongziliang committed
2
 * MIT License
xzl committed
3
 *
xiongziliang committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 * 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.
xzl committed
25
 */
26

xiongzilaing committed
27
#include <atomic>
xiongziliang committed
28
#include "Common/config.h"
xiongzilaing committed
29
#include "UDPServer.h"
xzl committed
30
#include "RtspSession.h"
xiongzilaing committed
31
#include "Util/mini.h"
32
#include "Util/MD5.h"
xiongziliang committed
33
#include "Util/base64.h"
xiongzilaing committed
34
#include "Util/onceToken.h"
xzl committed
35 36
#include "Util/TimeTicker.h"
#include "Util/NoticeCenter.h"
xiongzilaing committed
37
#include "Network/sockutil.h"
xzl committed
38

xiongziliang committed
39 40
using namespace std;
using namespace toolkit;
xzl committed
41

xiongziliang committed
42
namespace mediakit {
xzl committed
43

44 45
static int kSockFlags = SOCKET_DEFAULE_FLAGS | FLAG_MORE;

xzl committed
46 47 48 49 50 51 52 53 54 55 56 57
string dateHeader() {
	char buf[200];
	time_t tt = time(NULL);
	strftime(buf, sizeof buf, "Date: %a, %b %d %Y %H:%M:%S GMT\r\n", gmtime(&tt));
	return buf;
}

unordered_map<string, weak_ptr<RtspSession> > RtspSession::g_mapGetter;
unordered_map<void *, std::shared_ptr<RtspSession> > RtspSession::g_mapPostter;
recursive_mutex RtspSession::g_mtxGetter; //对quicktime上锁保护
recursive_mutex RtspSession::g_mtxPostter; //对quicktime上锁保护
RtspSession::RtspSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::Ptr &pSock) :
58
		TcpSession(pTh, pSock), _pSender(pSock) {
xiongziliang committed
59 60 61 62
	//设置10秒发送缓存
	pSock->setSendBufSecond(10);
	//设置15秒发送超时时间
	pSock->setSendTimeOutSecond(15);
xzl committed
63

64
	DebugL <<  get_peer_ip();
xzl committed
65 66 67
}

RtspSession::~RtspSession() {
68 69
	if (_onDestory) {
		_onDestory();
xzl committed
70
	}
71
    DebugL <<  get_peer_ip();
xzl committed
72 73 74
}

void RtspSession::shutdown(){
xiongziliang committed
75 76 77
	shutdown_l(true);
}
void RtspSession::shutdown_l(bool close){
78
	if (_sock) {
xiongziliang committed
79
		_sock->emitErr(SockException(Err_other, "self shutdown"),close);
xzl committed
80
	}
81
	if (_bBase64need && !_sock) {
xzl committed
82 83 84 85
		//quickTime http postter,and self is detached from tcpServer
		lock_guard<recursive_mutex> lock(g_mtxPostter);
		g_mapPostter.erase(this);
	}
86 87 88
	if (_pBrdcaster) {
		_pBrdcaster->setDetachCB(this, nullptr);
		_pBrdcaster.reset();
xzl committed
89
	}
90 91
	if (_pRtpReader) {
		_pRtpReader.reset();
xzl committed
92 93 94 95 96
	}
}

void RtspSession::onError(const SockException& err) {
	TraceL << err.getErrCode() << " " << err.what();
97
	if (_bListenPeerUdpData) {
xiongziliang committed
98
		//取消UDP端口监听
99
		UDPServer::Instance().stopListenPeer(get_peer_ip().data(), this);
100
		_bListenPeerUdpData = false;
xzl committed
101
	}
102
	if (!_bBase64need && _strSessionCookie.size() != 0) {
xzl committed
103 104
		//quickTime http getter
		lock_guard<recursive_mutex> lock(g_mtxGetter);
105
		g_mapGetter.erase(_strSessionCookie);
xzl committed
106 107
	}

108
	if (_bBase64need && err.getErrCode() == Err_eof) {
xzl committed
109
		//quickTime http postter,正在发送rtp; QuickTime只是断开了请求连接,请继续发送rtp
110
		_sock = nullptr;
xzl committed
111 112
		lock_guard<recursive_mutex> lock(g_mtxPostter);
		//为了保证脱离TCPServer后还能正常运作,需要保持本对象的强引用
xiongziliang committed
113 114 115 116
		try {
			g_mapPostter.emplace(this, dynamic_pointer_cast<RtspSession>(shared_from_this()));
		}catch (std::exception &ex){
		}
117
		TraceL << "quickTime will not send request any more!";
xzl committed
118
	}
119 120

    //流量统计事件广播
121
    GET_CONFIG_AND_REGISTER(uint32_t,iFlowThreshold,Broadcast::kFlowThreshold);
122
    if(_ui64TotalBytes > iFlowThreshold * 1024){
123
        NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,
124 125 126
										   _mediaInfo,
										   _ui64TotalBytes,
										   _ticker.createdTime()/1000,
127
										   *this);
128
    }
xzl committed
129 130 131
}

void RtspSession::onManager() {
132 133
	if (_ticker.createdTime() > 15 * 1000) {
		if (_strSession.size() == 0) {
134
			WarnL << "非法链接:" << get_peer_ip();
xzl committed
135 136 137 138
			shutdown();
			return;
		}
	}
139
	if (_rtpType != PlayerBase::RTP_TCP && _ticker.elapsedTime() > 15 * 1000) {
140
		WarnL << "RTSP会话超时:" << get_peer_ip();
xzl committed
141 142 143 144 145
		shutdown();
		return;
	}
}

xiongziliang committed
146

147
int64_t RtspSession::onRecvHeader(const char *header,uint64_t len) {
148
    char tmp[2 * 1024];
149
    _pcBuf = tmp;
150

151 152 153
	_parser.Parse(header); //rtsp请求解析
	string strCmd = _parser.Method(); //提取出请求命令字
	_iCseq = atoi(_parser["CSeq"].data());
xzl committed
154

xiongziliang committed
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
	typedef bool (RtspSession::*rtspCMDHandle)();
	static unordered_map<string, rtspCMDHandle> g_mapCmd;
	static onceToken token( []() {
		g_mapCmd.emplace("OPTIONS",&RtspSession::handleReq_Options);
		g_mapCmd.emplace("DESCRIBE",&RtspSession::handleReq_Describe);
		g_mapCmd.emplace("SETUP",&RtspSession::handleReq_Setup);
		g_mapCmd.emplace("PLAY",&RtspSession::handleReq_Play);
		g_mapCmd.emplace("PAUSE",&RtspSession::handleReq_Pause);
		g_mapCmd.emplace("TEARDOWN",&RtspSession::handleReq_Teardown);
		g_mapCmd.emplace("GET",&RtspSession::handleReq_Get);
		g_mapCmd.emplace("POST",&RtspSession::handleReq_Post);
		g_mapCmd.emplace("SET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER);
		g_mapCmd.emplace("GET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER);
	}, []() {});

xzl committed
170 171 172
	auto it = g_mapCmd.find(strCmd);
	if (it != g_mapCmd.end()) {
		auto fun = it->second;
xiongziliang committed
173 174 175 176
		if(!(this->*fun)()){
		    shutdown();
		}
	} else{
xzl committed
177 178 179
		shutdown();
		WarnL << "cmd=" << strCmd;
	}
xiongziliang committed
180

181
    _parser.Clear();
xiongziliang committed
182 183 184 185 186
    return 0;
}


void RtspSession::onRecv(const Buffer::Ptr &pBuf) {
187 188 189
	_ticker.resetTime();
    _ui64TotalBytes += pBuf->size();
    if (_bBase64need) {
xiongziliang committed
190
		//quicktime 加密后的rtsp请求,需要解密
191 192
		auto str = decodeBase64(string(pBuf->data(),pBuf->size()));
		inputRtspOrRtcp(str.data(),str.size());
xiongziliang committed
193
	} else {
194
        inputRtspOrRtcp(pBuf->data(),pBuf->size());
xiongziliang committed
195 196 197
	}
}

198
void RtspSession::inputRtspOrRtcp(const char *data,uint64_t len) {
199
	if(data[0] == '$' && _rtpType == PlayerBase::RTP_TCP){
xiongziliang committed
200 201 202
		//这是rtcp
		return;
	}
203
    input(data,len);
xzl committed
204 205 206 207
}

bool RtspSession::handleReq_Options() {
//支持这些命令
208
	int n = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
xzl committed
209 210 211 212 213
			"CSeq: %d\r\n"
			"Server: %s-%0.2f(build in %s)\r\n"
			"%s"
			"Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY,"
			" PAUSE, SET_PARAMETER, GET_PARAMETER\r\n\r\n",
214
			_iCseq, SERVER_NAME,
xzl committed
215 216
			RTSP_VERSION, RTSP_BUILDTIME,
			dateHeader().data());
217
	SocketHelper::send(_pcBuf, n);
xzl committed
218 219 220 221
	return true;
}

bool RtspSession::handleReq_Describe() {
222 223
    {
        //解析url获取媒体名称
224 225
        _strUrl = _parser.Url();
        _mediaInfo.parse(_parser.FullUrl());
226 227
    }

xzl committed
228 229 230 231 232
	if (!findStream()) {
		//未找到相应的MediaSource
		send_StreamNotFound();
		return false;
	}
233 234 235

    weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
    //该请求中的认证信息
236
    auto authorization = _parser["Authorization"];
237 238 239 240 241 242 243 244 245 246 247
    onGetRealm invoker = [weakSelf,authorization](const string &realm){
        if(realm.empty()){
            //无需认证,回复sdp
            onAuthSuccess(weakSelf);
            return;
        }
        //该流需要认证
        onAuthUser(weakSelf,realm,authorization);
    };

    //广播是否需要认证事件
248
    if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnGetRtspRealm,
249
                                           _mediaInfo,
250 251
                                           invoker,
                                            *this)){
252 253 254 255
        //无人监听此事件,说明无需认证
        invoker("");
    }
    return true;
xzl committed
256
}
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
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;
        }
        char response[2 * 1024];
        int n = sprintf(response,
                        "RTSP/1.0 200 OK\r\n"
                        "CSeq: %d\r\n"
                        "Server: %s-%0.2f(build in %s)\r\n"
                        "%s"
                        "x-Accept-Retransmit: our-retransmit\r\n"
                        "x-Accept-Dynamic-Rate: 1\r\n"
                        "Content-Base: %s/\r\n"
                        "Content-Type: application/sdp\r\n"
                        "Content-Length: %d\r\n\r\n%s",
280
                        strongSelf->_iCseq, SERVER_NAME,
281
                        RTSP_VERSION, RTSP_BUILDTIME,
282 283
                        dateHeader().data(), strongSelf->_strUrl.data(),
                        (int) strongSelf->_strSdp.length(), strongSelf->_strSdp.data());
284
        strongSelf->SocketHelper::send(response, n);
285 286 287 288 289 290 291 292 293 294 295 296 297 298
    });
}
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;
        }
xzl committed
299

300 301
        int n;
        char response[2 * 1024];
xiongziliang committed
302
        GET_CONFIG_AND_REGISTER(bool,authBasic,Rtsp::kAuthBasic);
303 304
        if (!authBasic) {
            //我们需要客户端优先以md5方式认证
305
            strongSelf->_strNonce = makeRandStr(32);
306 307 308 309 310
            n = sprintf(response,
                        "RTSP/1.0 401 Unauthorized\r\n"
                        "CSeq: %d\r\n"
                        "Server: %s-%0.2f(build in %s)\r\n"
                        "%s"
311
                        "WWW-Authenticate: Digest realm=\"%s\",nonce=\"%s\"\r\n\r\n",
312
                        strongSelf->_iCseq, SERVER_NAME,
313
                        RTSP_VERSION, RTSP_BUILDTIME,
314
                        dateHeader().data(), realm.data(), strongSelf->_strNonce.data());
315 316 317 318 319 320 321
        }else {
            //当然我们也支持base64认证,但是我们不建议这样做
            n = sprintf(response,
                        "RTSP/1.0 401 Unauthorized\r\n"
                        "CSeq: %d\r\n"
                        "Server: %s-%0.2f(build in %s)\r\n"
                        "%s"
322
                        "WWW-Authenticate: Basic realm=\"%s\"\r\n\r\n",
323
                        strongSelf->_iCseq, SERVER_NAME,
324 325 326
                        RTSP_VERSION, RTSP_BUILDTIME,
                        dateHeader().data(), realm.data());
        }
327
        strongSelf->SocketHelper::send(response, n);
328 329 330 331 332 333 334
    });
}

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());
335
    auto user_pwd_vec = split(user_pwd_buf,":");
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
    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);
        }
    };
352 353 354 355 356 357 358

    auto strongSelf = weakSelf.lock();
    if(!strongSelf){
        //本对象已销毁
        return;
    }

359
    //此时必须提供明文密码
360
    if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth,strongSelf->_mediaInfo,user, true,invoker,*strongSelf)){
361 362 363 364 365 366 367
        //表明该流需要认证却没监听请求密码事件,这一般是大意的程序所为,警告之
        WarnL << "请监听kBroadcastOnRtspAuth事件!";
        //但是我们还是忽略认证以便完成播放
        //我们输入的密码是明文
        invoker(false,pwd);
    }
}
368

369 370 371 372 373 374 375 376 377 378
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){
379
        map[trim(string(pr.first)," \"")] = trim(pr.second," \"");
380 381 382 383 384 385 386 387 388
    }
    //check realm
    if(realm != map["realm"]){
        TraceL << "realm not mached:" << realm << "," << map["realm"];
        onAuthFailed(weakSelf,realm);
        return ;
    }
    //check nonce
    auto nonce = map["nonce"];
389 390
    if(strongSelf->_strNonce != nonce){
        TraceL << "nonce not mached:" << nonce << "," << strongSelf->_strNonce;
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
        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();
        if(strcasecmp(good_response.data(),response.data()) == 0){
            //认证成功!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加密的密码
441
    if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth,strongSelf->_mediaInfo,username, false,invoker,*strongSelf)){
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
        //表明该流需要认证却没监听请求密码事件,这一般是大意的程序所为,警告之
        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);
    }
}
xzl committed
469
inline void RtspSession::send_StreamNotFound() {
470
	int n = sprintf(_pcBuf, "RTSP/1.0 404 Stream Not Found\r\n"
xzl committed
471 472 473 474
			"CSeq: %d\r\n"
			"Server: %s-%0.2f(build in %s)\r\n"
			"%s"
			"Connection: Close\r\n\r\n",
475
			_iCseq, SERVER_NAME,
xzl committed
476 477
			RTSP_VERSION, RTSP_BUILDTIME,
			dateHeader().data());
478
	SocketHelper::send(_pcBuf, n);
xzl committed
479 480
}
inline void RtspSession::send_UnsupportedTransport() {
481
	int n = sprintf(_pcBuf, "RTSP/1.0 461 Unsupported Transport\r\n"
xzl committed
482 483 484 485
			"CSeq: %d\r\n"
			"Server: %s-%0.2f(build in %s)\r\n"
			"%s"
			"Connection: Close\r\n\r\n",
486
			_iCseq, SERVER_NAME,
xzl committed
487 488
			RTSP_VERSION, RTSP_BUILDTIME,
			dateHeader().data());
489
	SocketHelper::send(_pcBuf, n);
xzl committed
490 491 492
}

inline void RtspSession::send_SessionNotFound() {
493
	int n = sprintf(_pcBuf, "RTSP/1.0 454 Session Not Found\r\n"
xzl committed
494 495 496 497
			"CSeq: %d\r\n"
			"Server: %s-%0.2f(build in %s)\r\n"
			"%s"
			"Connection: Close\r\n\r\n",
498
			_iCseq, SERVER_NAME,
xzl committed
499 500
			RTSP_VERSION, RTSP_BUILDTIME,
			dateHeader().data());
501
	SocketHelper::send(_pcBuf, n);
xzl committed
502

xiongziliang committed
503
	/*40 Method Not Allowed*/
xzl committed
504 505 506 507

}
bool RtspSession::handleReq_Setup() {
//处理setup命令,该函数可能进入多次
508
    auto controlSuffix = _parser.FullUrl().substr(1 + _parser.FullUrl().rfind('/'));
509
	int trackIdx = getTrackIndexByControlSuffix(controlSuffix);
xzl committed
510 511 512 513
	if (trackIdx == -1) {
		//未找到相应track
		return false;
	}
xiongziliang committed
514
	SdpTrack::Ptr &trackRef = _aTrackInfo[trackIdx];
515
	if (trackRef->_inited) {
xzl committed
516 517 518
		//已经初始化过该Track
		return false;
	}
519
	trackRef->_inited = true; //现在初始化
xzl committed
520

521
	auto strongRing = _pWeakRing.lock();
xzl committed
522 523 524 525 526 527
	if (!strongRing) {
		//the media source is released!
		send_NotAcceptable();
		return false;
	}

528 529 530
	if(!_bSetUped){
		_bSetUped = true;
		auto strTransport = _parser["Transport"];
xzl committed
531
		if(strTransport.find("TCP") != string::npos){
532
			_rtpType = PlayerBase::RTP_TCP;
xzl committed
533
		}else if(strTransport.find("multicast") != string::npos){
534
			_rtpType = PlayerBase::RTP_MULTICAST;
xzl committed
535
		}else{
536
			_rtpType = PlayerBase::RTP_UDP;
xzl committed
537 538 539
		}
	}

540 541
	if (!_pRtpReader && _rtpType != PlayerBase::RTP_MULTICAST) {
		_pRtpReader = strongRing->attach();
xzl committed
542
		weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
543
		_pRtpReader->setDetachCB([weakSelf]() {
xzl committed
544 545 546 547 548 549 550 551
			auto strongSelf = weakSelf.lock();
			if(!strongSelf) {
				return;
			}
			strongSelf->safeShutdown();
		});
	}

552
	switch (_rtpType) {
xzl committed
553
	case PlayerBase::RTP_TCP: {
554
		int iLen = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
xzl committed
555 556 557 558 559 560 561 562
				"CSeq: %d\r\n"
				"Server: %s-%0.2f(build in %s)\r\n"
				"%s"
				"Transport: RTP/AVP/TCP;unicast;"
				"interleaved=%d-%d;ssrc=%s;mode=play\r\n"
				"Session: %s\r\n"
				"x-Transport-Options: late-tolerance=1.400000\r\n"
				"x-Dynamic-Rate: 1\r\n\r\n",
563
				_iCseq, SERVER_NAME,
xzl committed
564
				RTSP_VERSION, RTSP_BUILDTIME,
565 566 567
				dateHeader().data(), trackRef->_type * 2,
                trackRef->_type * 2 + 1,
				printSSRC(trackRef->_ssrc).data(),
568 569
				_strSession.data());
		SocketHelper::send(_pcBuf, iLen);
xzl committed
570 571 572
	}
		break;
	case PlayerBase::RTP_UDP: {
xiongziliang committed
573
		//我们用trackIdx区分rtp和rtcp包
574
		auto pSockRtp = UDPServer::Instance().getSock(get_local_ip().data(),2*trackIdx);
xiongziliang committed
575 576 577 578 579 580
		if (!pSockRtp) {
			//分配端口失败
			WarnL << "分配rtp端口失败";
			send_NotAcceptable();
			return false;
		}
581
		auto pSockRtcp = UDPServer::Instance().getSock(get_local_ip().data(),2*trackIdx + 1 ,pSockRtp->get_local_port() + 1);
xiongziliang committed
582
		if (!pSockRtcp) {
xzl committed
583
			//分配端口失败
xiongziliang committed
584
			WarnL << "分配rtcp端口失败";
xzl committed
585 586 587
			send_NotAcceptable();
			return false;
		}
588
		_apUdpSock[trackIdx] = pSockRtp;
xiongziliang committed
589
		//设置客户端内网端口信息
590
		string strClientPort = FindField(_parser["Transport"].data(), "client_port=", NULL);
xzl committed
591 592 593 594
		uint16_t ui16PeerPort = atoi( FindField(strClientPort.data(), NULL, "-").data());
		struct sockaddr_in peerAddr;
		peerAddr.sin_family = AF_INET;
		peerAddr.sin_port = htons(ui16PeerPort);
595
		peerAddr.sin_addr.s_addr = inet_addr(get_peer_ip().data());
xzl committed
596
		bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero);
597
		_apPeerUdpAddr[trackIdx].reset((struct sockaddr *) (new struct sockaddr_in(peerAddr)));
xiongziliang committed
598 599
		//尝试获取客户端nat映射地址
		startListenPeerUdpData();
xzl committed
600
		//InfoL << "分配端口:" << srv_port;
601
		int n = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
xzl committed
602 603 604 605 606 607
				"CSeq: %d\r\n"
				"Server: %s-%0.2f(build in %s)\r\n"
				"%s"
				"Transport: RTP/AVP/UDP;unicast;"
				"client_port=%s;server_port=%d-%d;ssrc=%s;mode=play\r\n"
				"Session: %s\r\n\r\n",
608
				_iCseq, SERVER_NAME,
xzl committed
609 610
				RTSP_VERSION, RTSP_BUILDTIME,
				dateHeader().data(), strClientPort.data(),
xiongziliang committed
611
				pSockRtp->get_local_port(), pSockRtcp->get_local_port(),
612
				printSSRC(trackRef->_ssrc).data(),
613 614
				_strSession.data());
		SocketHelper::send(_pcBuf, n);
xzl committed
615 616 617
	}
		break;
	case PlayerBase::RTP_MULTICAST: {
618 619 620
		if(!_pBrdcaster){
			_pBrdcaster = RtpBroadCaster::get(get_local_ip(),_mediaInfo._vhost, _mediaInfo._app, _mediaInfo._streamid);
			if (!_pBrdcaster) {
xzl committed
621 622 623 624
				send_NotAcceptable();
				return false;
			}
			weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
625
			_pBrdcaster->setDetachCB(this, [weakSelf]() {
xzl committed
626 627 628 629 630 631 632
				auto strongSelf = weakSelf.lock();
				if(!strongSelf) {
					return;
				}
				strongSelf->safeShutdown();
			});
		}
633
		int iSrvPort = _pBrdcaster->getPort(trackRef->_type);
xiongziliang committed
634
		//我们用trackIdx区分rtp和rtcp包
635
		auto pSockRtcp = UDPServer::Instance().getSock(get_local_ip().data(),2*trackIdx + 1,iSrvPort + 1);
xiongziliang committed
636 637 638 639 640 641 642
		if (!pSockRtcp) {
			//分配端口失败
			WarnL << "分配rtcp端口失败";
			send_NotAcceptable();
			return false;
		}
		startListenPeerUdpData();
643
        GET_CONFIG_AND_REGISTER(uint32_t,udpTTL,MultiCast::kUdpTTL);
644
        int n = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
xzl committed
645 646 647 648 649 650
				"CSeq: %d\r\n"
				"Server: %s-%0.2f(build in %s)\r\n"
				"%s"
				"Transport: RTP/AVP;multicast;destination=%s;"
				"source=%s;port=%d-%d;ttl=%d;ssrc=%s\r\n"
				"Session: %s\r\n\r\n",
651
				_iCseq, SERVER_NAME,
xzl committed
652
				RTSP_VERSION, RTSP_BUILDTIME,
653
				dateHeader().data(), _pBrdcaster->getIP().data(),
654
				get_local_ip().data(), iSrvPort, pSockRtcp->get_local_port(),
655
				udpTTL,printSSRC(trackRef->_ssrc).data(),
656 657
				_strSession.data());
		SocketHelper::send(_pcBuf, n);
xzl committed
658 659 660 661 662 663 664 665 666
	}
		break;
	default:
		break;
	}
	return true;
}

bool RtspSession::handleReq_Play() {
xiongziliang committed
667
	if (_aTrackInfo.size() == 0) {
xzl committed
668 669 670
		//还没有Describe
		return false;
	}
671
	if (_parser["Session"] != _strSession) {
xzl committed
672 673 674
		send_SessionNotFound();
		return false;
	}
675
	auto strRange = _parser["Range"];
676
    auto onRes = [this,strRange](const string &err){
677
        bool authSuccess = err.empty();
678
        char response[2 * 1024];
679 680
        _pcBuf = response;
        if(!authSuccess && _bFirstPlay){
681
            //第一次play是播放,否则是恢复播放。只对播放鉴权
682
            int n = sprintf(_pcBuf,
683 684 685
                            "RTSP/1.0 401 Unauthorized\r\n"
                            "CSeq: %d\r\n"
                            "Server: %s-%0.2f(build in %s)\r\n"
686 687 688
                            "%s"
                            "Content-Type: text/plain\r\n"
                            "Content-Length: %d\r\n\r\n%s",
689
                            _iCseq, SERVER_NAME,
690 691
                            RTSP_VERSION, RTSP_BUILDTIME,
                            dateHeader().data(),(int)err.size(),err.data());
692
			SocketHelper::send(_pcBuf,n);
693 694 695
            shutdown();
            return;
        }
696
        if(_pRtpReader){
697
            weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
698 699
            SockUtil::setNoDelay(_pSender->rawFD(), false);
            _pRtpReader->setReadCB([weakSelf](const RtpPacket::Ptr &pack) {
700 701 702 703 704 705 706 707 708 709 710 711 712 713
                auto strongSelf = weakSelf.lock();
                if(!strongSelf) {
                    return;
                }
                strongSelf->async([weakSelf,pack](){
                    auto strongSelf = weakSelf.lock();
                    if(!strongSelf) {
                        return;
                    }
                    strongSelf->sendRtpPacket(pack);
                });

            });
        }
xzl committed
714

715
        auto pMediaSrc = _pMediaSrc.lock();
716 717
        uint32_t iStamp = 0;
        if(pMediaSrc){
718
            if (strRange.size() && !_bFirstPlay) {
719 720 721 722
                auto strStart = FindField(strRange.data(), "npt=", "-");
                if (strStart == "now") {
                    strStart = "0";
                }
723 724 725
                auto iStartTime = 1000 * atof(strStart.data());
                InfoL << "rtsp seekTo(ms):" << iStartTime;
                pMediaSrc->seekTo(iStartTime);
726
                iStamp = pMediaSrc->getTimeStamp(TrackInvalid);
727 728 729 730 731
            }else if(pMediaSrc->getRing()->readerCount() == 1){
                //第一个消费者
                pMediaSrc->seekTo(0);
                iStamp = 0;
            }else{
732
                iStamp = pMediaSrc->getTimeStamp(TrackInvalid);
733
            }
xiongziliang committed
734 735

            for(auto &track : _aTrackInfo){
736 737
				track->_ssrc = pMediaSrc->getSsrc(track->_type);
				track->_seq = pMediaSrc->getSeqence(track->_type);
738
				track->_time_stamp = pMediaSrc->getTimeStamp(track->_type);
739 740
            }
        }
741 742
        _bFirstPlay = false;
        int iLen = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
743 744 745 746 747
                                   "CSeq: %d\r\n"
                                   "Server: %s-%0.2f(build in %s)\r\n"
                                   "%s"
                                   "Session: %s\r\n"
                                   "Range: npt=%.2f-\r\n"
748 749
                                   "RTP-Info: ", _iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
                           dateHeader().data(), _strSession.data(),iStamp/1000.0);
750

xiongziliang committed
751
		for(auto &track : _aTrackInfo){
752
			if (track->_inited == false) {
xiongziliang committed
753 754 755 756
				//还有track没有setup
				shutdown();
				return;
			}
757 758 759 760 761
			iLen += sprintf(_pcBuf + iLen, "url=%s/%s;seq=%d;rtptime=%u,",
							_strUrl.data(),
							track->_control_surffix.data(),
							track->_seq,
							track->_time_stamp * track->_samplerate / 1000);
xiongziliang committed
762 763
		}

764
        iLen -= 1;
765 766 767
        (_pcBuf)[iLen] = '\0';
        iLen += sprintf(_pcBuf + iLen, "\r\n\r\n");
		SocketHelper::send(_pcBuf, iLen);
768 769 770

		//提高发送性能
		(*this) << SocketFlags(kSockFlags);
771
		SockUtil::setNoDelay(_pSender->rawFD(),false);
772
    };
xzl committed
773

774
    weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
775
    Broadcast::AuthInvoker invoker = [weakSelf,onRes](const string &err){
776 777 778
        auto strongSelf = weakSelf.lock();
        if(!strongSelf){
            return;
xzl committed
779
        }
780
        strongSelf->async([weakSelf,onRes,err](){
781 782 783 784
            auto strongSelf = weakSelf.lock();
            if(!strongSelf){
                return;
            }
785
            onRes(err);
786 787
        });
    };
788
    auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,_mediaInfo,invoker,*this);
789 790
    if(!flag){
        //该事件无人监听,默认不鉴权
791
        onRes("");
792
    }
xzl committed
793 794 795 796
	return true;
}

bool RtspSession::handleReq_Pause() {
797
	if (_parser["Session"] != _strSession) {
xzl committed
798 799 800
		send_SessionNotFound();
		return false;
	}
801
	int n = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
xzl committed
802 803 804
			"CSeq: %d\r\n"
			"Server: %s-%0.2f(build in %s)\r\n"
			"%s"
805 806 807 808 809
			"Session: %s\r\n\r\n", _iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
			dateHeader().data(), _strSession.data());
	SocketHelper::send(_pcBuf, n);
	if(_pRtpReader){
		_pRtpReader->setReadCB(nullptr);
xzl committed
810 811 812 813 814 815
	}
	return true;

}

bool RtspSession::handleReq_Teardown() {
816
	int n = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
xzl committed
817 818 819
			"CSeq: %d\r\n"
			"Server: %s-%0.2f(build in %s)\r\n"
			"%s"
820 821
			"Session: %s\r\n\r\n", _iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
			dateHeader().data(), _strSession.data());
xzl committed
822

823
	SocketHelper::send(_pcBuf, n);
xzl committed
824 825 826 827 828
	TraceL << "播放器断开连接!";
	return false;
}

bool RtspSession::handleReq_Get() {
829 830
	_strSessionCookie = _parser["x-sessioncookie"];
	int n = sprintf(_pcBuf, "HTTP/1.0 200 OK\r\n"
xzl committed
831 832 833 834 835 836 837 838
			"%s"
			"Connection: close\r\n"
			"Cache-Control: no-store\r\n"
			"Pragma: no-cache\r\n"
			"Content-Type: application/x-rtsp-tunnelled\r\n\r\n",
			dateHeader().data());
//注册GET
	lock_guard<recursive_mutex> lock(g_mtxGetter);
839 840 841
	g_mapGetter[_strSessionCookie] = dynamic_pointer_cast<RtspSession>(shared_from_this());
	//InfoL << _strSessionCookie;
	SocketHelper::send(_pcBuf, n);
xzl committed
842 843 844 845 846 847
	return true;

}

bool RtspSession::handleReq_Post() {
	lock_guard<recursive_mutex> lock(g_mtxGetter);
848
	string sessioncookie = _parser["x-sessioncookie"];
xzl committed
849 850 851
//Poster 找到 Getter
	auto it = g_mapGetter.find(sessioncookie);
	if (it == g_mapGetter.end()) {
xiongziliang committed
852
		//WarnL << sessioncookie;
xzl committed
853 854
		return false;
	}
855
	_bBase64need = true;
xzl committed
856 857 858 859 860
//Poster 找到Getter的SOCK
	auto strongSession = it->second.lock();
	g_mapGetter.erase(sessioncookie);
	if (!strongSession) {
		send_SessionNotFound();
xiongziliang committed
861
		//WarnL;
xzl committed
862 863 864 865 866 867 868 869
		return false;
	}
	initSender(strongSession);
	return true;
}

bool RtspSession::handleReq_SET_PARAMETER() {
	//TraceL<<endl;
870
	int n = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
xzl committed
871 872 873
			"CSeq: %d\r\n"
			"Server: %s-%0.2f(build in %s)\r\n"
			"%s"
874 875 876
			"Session: %s\r\n\r\n", _iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
			dateHeader().data(), _strSession.data());
	SocketHelper::send(_pcBuf, n);
xzl committed
877 878 879 880
	return true;
}

inline void RtspSession::send_NotAcceptable() {
881
	int n = sprintf(_pcBuf, "RTSP/1.0 406 Not Acceptable\r\n"
xzl committed
882 883 884
			"CSeq: %d\r\n"
			"Server: %s-%0.2f(build in %s)\r\n"
			"%s"
885
			"Connection: Close\r\n\r\n", _iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
xzl committed
886
			dateHeader().data());
887
	SocketHelper::send(_pcBuf, n);
xzl committed
888 889

}
890

xzl committed
891
inline bool RtspSession::findStream() {
892
	RtspMediaSource::Ptr pMediaSrc =
893
    dynamic_pointer_cast<RtspMediaSource>( MediaSource::find(RTSP_SCHEMA,_mediaInfo._vhost, _mediaInfo._app,_mediaInfo._streamid) );
xzl committed
894
	if (!pMediaSrc) {
895
		WarnL << "No such stream:" <<  _mediaInfo._vhost << " " <<  _mediaInfo._app << " " << _mediaInfo._streamid;
xzl committed
896 897
		return false;
	}
898 899
	_strSdp = pMediaSrc->getSdp();
	_pWeakRing = pMediaSrc->getRing();
xzl committed
900

xiongziliang committed
901 902 903
	_sdpAttr.load(_strSdp);
	_aTrackInfo = _sdpAttr.getAvailableTrack();

xiongziliang committed
904
	if (_aTrackInfo.empty()) {
xzl committed
905 906
		return false;
	}
907 908
	_strSession = makeRandStr(12);
	_pMediaSrc = pMediaSrc;
xzl committed
909

xiongziliang committed
910
	for(auto &track : _aTrackInfo){
911 912
		track->_ssrc = pMediaSrc->getSsrc(track->_type);
		track->_seq = pMediaSrc->getSeqence(track->_type);
913
		track->_time_stamp = pMediaSrc->getTimeStamp(track->_type);
xzl committed
914 915 916 917
	}
	return true;
}

918 919

inline void RtspSession::sendRtpPacket(const RtpPacket::Ptr & pkt) {
xzl committed
920
	//InfoL<<(int)pkt.Interleaved;
921
	switch (_rtpType) {
xzl committed
922
	case PlayerBase::RTP_TCP: {
923 924
        BufferRtp::Ptr buffer(new BufferRtp(pkt));
		send(buffer);
xzl committed
925 926
#ifdef RTSP_SEND_RTCP
		int iTrackIndex = getTrackIndexByTrackId(pkt.interleaved / 2);
927
		RtcpCounter &counter = _aRtcpCnt[iTrackIndex];
xzl committed
928 929
		counter.pktCnt += 1;
		counter.octCount += (pkt.length - 12);
930 931
		auto &_ticker = _aRtcpTicker[iTrackIndex];
		if (_ticker.elapsedTime() > 5 * 1000) {
xzl committed
932
			//send rtcp every 5 second
933
			_ticker.resetTime();
xzl committed
934 935 936 937 938 939 940
			counter.timeStamp = pkt.timeStamp;
			sendRTCP();
		}
#endif
	}
		break;
	case PlayerBase::RTP_UDP: {
xiongziliang committed
941
		int iTrackIndex = getTrackIndexByTrackType(pkt->type);
942
		auto pSock = _apUdpSock[iTrackIndex].lock();
xzl committed
943 944 945 946
		if (!pSock) {
			shutdown();
			return;
		}
947
		auto peerAddr = _apPeerUdpAddr[iTrackIndex];
xzl committed
948 949 950
		if (!peerAddr) {
			return;
		}
951
        BufferRtp::Ptr buffer(new BufferRtp(pkt,4));
952
        _ui64TotalBytes += buffer->size();
953
        pSock->send(buffer,kSockFlags, peerAddr.get());
xzl committed
954 955 956 957 958 959 960
	}
		break;
	default:
		break;
	}
}

961
inline void RtspSession::onRcvPeerUdpData(int iTrackIdx, const Buffer::Ptr &pBuf, const struct sockaddr& addr) {
xiongziliang committed
962 963
	if(iTrackIdx % 2 == 0){
		//这是rtp探测包
964
		if(!_bGotAllPeerUdp){
xiongziliang committed
965
			//还没有获取完整的rtp探测包
966
			if(SockUtil::in_same_lan(get_local_ip().data(),get_peer_ip().data())){
xiongziliang committed
967
				//在内网中,客户端上报的端口号是真实的,所以我们忽略udp打洞包
968
				_bGotAllPeerUdp = true;
xiongziliang committed
969 970 971
				return;
			}
			//设置真实的客户端nat映射端口号
972 973 974
			_apPeerUdpAddr[iTrackIdx / 2].reset(new struct sockaddr(addr));
			_abGotPeerUdp[iTrackIdx / 2] = true;
			_bGotAllPeerUdp = true;//先假设获取到完整的rtp探测包
xiongziliang committed
975
			for (unsigned int i = 0; i < _aTrackInfo.size(); i++) {
976
				if (!_abGotPeerUdp[i]) {
xiongziliang committed
977
					//还有track没获取到rtp探测包
978
					_bGotAllPeerUdp = false;
xiongziliang committed
979 980 981
					break;
				}
			}
xzl committed
982
		}
xiongziliang committed
983 984
	}else{
		//这是rtcp心跳包,说明播放器还存活
985
		_ticker.resetTime();
xiongziliang committed
986
		//TraceL << "rtcp:" << (iTrackIdx-1)/2 ;
xzl committed
987 988 989 990
	}
}


xiongziliang committed
991
inline void RtspSession::startListenPeerUdpData() {
992
	_bListenPeerUdpData = true;
xzl committed
993
	weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
994 995
	UDPServer::Instance().listenPeer(get_peer_ip().data(), this,
			[weakSelf](int iTrackIdx,const Buffer::Ptr &pBuf,struct sockaddr *pPeerAddr)->bool {
xzl committed
996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
				auto strongSelf=weakSelf.lock();
				if(!strongSelf) {
					return false;
				}
				struct sockaddr addr=*pPeerAddr;
				strongSelf->async_first([weakSelf,pBuf,addr,iTrackIdx]() {
							auto strongSelf=weakSelf.lock();
							if(!strongSelf) {
								return;
							}
							strongSelf->onRcvPeerUdpData(iTrackIdx,pBuf,addr);
						});
				return true;
			});
}

inline void RtspSession::initSender(const std::shared_ptr<RtspSession>& session) {
1013
	_pSender = session->_sock;
xzl committed
1014
	weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
1015
	session->_onDestory = [weakSelf]() {
xzl committed
1016
		auto strongSelf=weakSelf.lock();
xiongziliang committed
1017 1018 1019 1020
        if(!strongSelf) {
            return;
        }
        //DebugL;
1021
        strongSelf->_pSender->setOnErr([weakSelf](const SockException &err) {
xzl committed
1022 1023 1024 1025 1026 1027 1028
			auto strongSelf=weakSelf.lock();
			if(!strongSelf) {
				return;
			}
			strongSelf->safeShutdown();
		});
	};
xiongziliang committed
1029
	session->shutdown_l(false);
xzl committed
1030 1031 1032 1033 1034 1035 1036
}

#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;
1037 1038 1039
	for (uint8_t i = 0; i < _uiTrackCnt; i++) {
		auto &track = _aTrackInfo[i];
		auto &counter = _aRtcpCnt[i];
xzl committed
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092

		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

}
xiongziliang committed
1093
/* namespace mediakit */
xzl committed
1094