RtspSession.cpp 34.9 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 39 40 41 42 43 44 45

using namespace Config;
using namespace ZL::Util;
using namespace ZL::Network;

namespace ZL {
namespace Rtsp {

46 47
static int kSockFlags = SOCKET_DEFAULE_FLAGS | FLAG_MORE;

xzl committed
48 49 50 51 52 53 54 55 56 57 58 59
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) :
60
		TcpSession(pTh, pSock), m_pSender(pSock) {
xiongziliang committed
61 62 63 64
	//设置10秒发送缓存
	pSock->setSendBufSecond(10);
	//设置15秒发送超时时间
	pSock->setSendTimeOutSecond(15);
xzl committed
65

66
	DebugL <<  get_peer_ip();
xzl committed
67 68 69 70 71 72
}

RtspSession::~RtspSession() {
	if (m_onDestory) {
		m_onDestory();
	}
73
    DebugL <<  get_peer_ip();
xzl committed
74 75 76
}

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

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

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

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

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

xiongziliang committed
148

149
int64_t RtspSession::onRecvHeader(const char *header,uint64_t len) {
150 151 152
    char tmp[2 * 1024];
    m_pcBuf = tmp;

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

xiongziliang committed
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
	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
172 173 174
	auto it = g_mapCmd.find(strCmd);
	if (it != g_mapCmd.end()) {
		auto fun = it->second;
xiongziliang committed
175 176 177 178
		if(!(this->*fun)()){
		    shutdown();
		}
	} else{
xzl committed
179 180 181
		shutdown();
		WarnL << "cmd=" << strCmd;
	}
xiongziliang committed
182 183 184 185 186 187 188 189 190 191 192

    m_parser.Clear();
    return 0;
}


void RtspSession::onRecv(const Buffer::Ptr &pBuf) {
	m_ticker.resetTime();
    m_ui64TotalBytes += pBuf->size();
    if (m_bBase64need) {
		//quicktime 加密后的rtsp请求,需要解密
193 194
		auto str = decodeBase64(string(pBuf->data(),pBuf->size()));
		inputRtspOrRtcp(str.data(),str.size());
xiongziliang committed
195
	} else {
196
        inputRtspOrRtcp(pBuf->data(),pBuf->size());
xiongziliang committed
197 198 199
	}
}

200 201
void RtspSession::inputRtspOrRtcp(const char *data,uint64_t len) {
	if(data[0] == '$' && m_rtpType == PlayerBase::RTP_TCP){
xiongziliang committed
202 203 204
		//这是rtcp
		return;
	}
205
    input(data,len);
xzl committed
206 207 208 209 210 211 212 213 214 215
}

bool RtspSession::handleReq_Options() {
//支持这些命令
	int n = sprintf(m_pcBuf, "RTSP/1.0 200 OK\r\n"
			"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",
216
			m_iCseq, SERVER_NAME,
xzl committed
217 218
			RTSP_VERSION, RTSP_BUILDTIME,
			dateHeader().data());
219
	SocketHelper::send(m_pcBuf, n);
xzl committed
220 221 222 223
	return true;
}

bool RtspSession::handleReq_Describe() {
224 225 226
    {
        //解析url获取媒体名称
        m_strUrl = m_parser.Url();
227
        m_mediaInfo.parse(m_parser.FullUrl());
228 229
    }

xzl committed
230 231 232 233 234
	if (!findStream()) {
		//未找到相应的MediaSource
		send_StreamNotFound();
		return false;
	}
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249

    weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
    //该请求中的认证信息
    auto authorization = m_parser["Authorization"];
    onGetRealm invoker = [weakSelf,authorization](const string &realm){
        if(realm.empty()){
            //无需认证,回复sdp
            onAuthSuccess(weakSelf);
            return;
        }
        //该流需要认证
        onAuthUser(weakSelf,realm,authorization);
    };

    //广播是否需要认证事件
250
    if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnGetRtspRealm,
xiongziliang committed
251
                                           m_mediaInfo,
252 253
                                           invoker,
                                            *this)){
254 255 256 257
        //无人监听此事件,说明无需认证
        invoker("");
    }
    return true;
xzl committed
258
}
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
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",
282
                        strongSelf->m_iCseq, SERVER_NAME,
283 284 285
                        RTSP_VERSION, RTSP_BUILDTIME,
                        dateHeader().data(), strongSelf->m_strUrl.data(),
                        (int) strongSelf->m_strSdp.length(), strongSelf->m_strSdp.data());
286
        strongSelf->SocketHelper::send(response, n);
287 288 289 290 291 292 293 294 295 296 297 298 299 300
    });
}
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
301

302 303
        int n;
        char response[2 * 1024];
304
        GET_CONFIG_AND_REGISTER(bool,authBasic,Config::Rtsp::kAuthBasic);
305 306 307 308 309 310 311 312
        if (!authBasic) {
            //我们需要客户端优先以md5方式认证
            strongSelf->m_strNonce = makeRandStr(32);
            n = sprintf(response,
                        "RTSP/1.0 401 Unauthorized\r\n"
                        "CSeq: %d\r\n"
                        "Server: %s-%0.2f(build in %s)\r\n"
                        "%s"
313
                        "WWW-Authenticate: Digest realm=\"%s\",nonce=\"%s\"\r\n\r\n",
314
                        strongSelf->m_iCseq, SERVER_NAME,
315 316 317 318 319 320 321 322 323
                        RTSP_VERSION, RTSP_BUILDTIME,
                        dateHeader().data(), realm.data(), strongSelf->m_strNonce.data());
        }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"
324
                        "WWW-Authenticate: Basic realm=\"%s\"\r\n\r\n",
325
                        strongSelf->m_iCseq, SERVER_NAME,
326 327 328
                        RTSP_VERSION, RTSP_BUILDTIME,
                        dateHeader().data(), realm.data());
        }
329
        strongSelf->SocketHelper::send(response, n);
330 331 332 333 334 335 336
    });
}

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

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

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

371 372 373 374 375 376 377 378 379 380
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){
381
        map[trim(string(pr.first)," \"")] = trim(pr.second," \"");
382 383 384 385 386 387 388 389 390 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 441 442
    }
    //check realm
    if(realm != map["realm"]){
        TraceL << "realm not mached:" << realm << "," << map["realm"];
        onAuthFailed(weakSelf,realm);
        return ;
    }
    //check nonce
    auto nonce = map["nonce"];
    if(strongSelf->m_strNonce != nonce){
        TraceL << "nonce not mached:" << nonce << "," << strongSelf->m_strNonce;
        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加密的密码
xiongziliang committed
443
    if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth,strongSelf->m_mediaInfo,username, false,invoker,*strongSelf)){
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 469 470
        //表明该流需要认证却没监听请求密码事件,这一般是大意的程序所为,警告之
        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
471 472 473 474 475 476
inline void RtspSession::send_StreamNotFound() {
	int n = sprintf(m_pcBuf, "RTSP/1.0 404 Stream Not Found\r\n"
			"CSeq: %d\r\n"
			"Server: %s-%0.2f(build in %s)\r\n"
			"%s"
			"Connection: Close\r\n\r\n",
477
			m_iCseq, SERVER_NAME,
xzl committed
478 479
			RTSP_VERSION, RTSP_BUILDTIME,
			dateHeader().data());
480
	SocketHelper::send(m_pcBuf, n);
xzl committed
481 482 483 484 485 486 487
}
inline void RtspSession::send_UnsupportedTransport() {
	int n = sprintf(m_pcBuf, "RTSP/1.0 461 Unsupported Transport\r\n"
			"CSeq: %d\r\n"
			"Server: %s-%0.2f(build in %s)\r\n"
			"%s"
			"Connection: Close\r\n\r\n",
488
			m_iCseq, SERVER_NAME,
xzl committed
489 490
			RTSP_VERSION, RTSP_BUILDTIME,
			dateHeader().data());
491
	SocketHelper::send(m_pcBuf, n);
xzl committed
492 493 494 495 496 497 498 499
}

inline void RtspSession::send_SessionNotFound() {
	int n = sprintf(m_pcBuf, "RTSP/1.0 454 Session Not Found\r\n"
			"CSeq: %d\r\n"
			"Server: %s-%0.2f(build in %s)\r\n"
			"%s"
			"Connection: Close\r\n\r\n",
500
			m_iCseq, SERVER_NAME,
xzl committed
501 502
			RTSP_VERSION, RTSP_BUILDTIME,
			dateHeader().data());
503
	SocketHelper::send(m_pcBuf, n);
xzl committed
504

xiongziliang committed
505
	/*40 Method Not Allowed*/
xzl committed
506 507 508 509

}
bool RtspSession::handleReq_Setup() {
//处理setup命令,该函数可能进入多次
xiongziliang committed
510
    auto controlSuffix = m_parser.FullUrl().substr(1 + m_parser.FullUrl().rfind('/'));
511
	int trackIdx = getTrackIndexByControlSuffix(controlSuffix);
xzl committed
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
	if (trackIdx == -1) {
		//未找到相应track
		return false;
	}
	RtspTrack &trackRef = m_aTrackInfo[trackIdx];
	if (trackRef.inited) {
		//已经初始化过该Track
		return false;
	}
	trackRef.inited = true; //现在初始化

	auto strongRing = m_pWeakRing.lock();
	if (!strongRing) {
		//the media source is released!
		send_NotAcceptable();
		return false;
	}

	if(!m_bSetUped){
		m_bSetUped = true;
		auto strTransport = m_parser["Transport"];
		if(strTransport.find("TCP") != string::npos){
			m_rtpType = PlayerBase::RTP_TCP;
		}else if(strTransport.find("multicast") != string::npos){
			m_rtpType = PlayerBase::RTP_MULTICAST;
		}else{
			m_rtpType = PlayerBase::RTP_UDP;
		}
	}

	if (!m_pRtpReader && m_rtpType != PlayerBase::RTP_MULTICAST) {
		m_pRtpReader = strongRing->attach();
		weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
		m_pRtpReader->setDetachCB([weakSelf]() {
			auto strongSelf = weakSelf.lock();
			if(!strongSelf) {
				return;
			}
			strongSelf->safeShutdown();
		});
	}

	switch (m_rtpType) {
	case PlayerBase::RTP_TCP: {
		int iLen = sprintf(m_pcBuf, "RTSP/1.0 200 OK\r\n"
				"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",
565
				m_iCseq, SERVER_NAME,
xzl committed
566
				RTSP_VERSION, RTSP_BUILDTIME,
xiongziliang committed
567 568
				dateHeader().data(), trackRef.type * 2,
                trackRef.type * 2 + 1,
xzl committed
569 570
				printSSRC(trackRef.ssrc).data(),
				m_strSession.data());
571
		SocketHelper::send(m_pcBuf, iLen);
xzl committed
572 573 574
	}
		break;
	case PlayerBase::RTP_UDP: {
xiongziliang committed
575
		//我们用trackIdx区分rtp和rtcp包
576
		auto pSockRtp = UDPServer::Instance().getSock(get_local_ip().data(),2*trackIdx);
xiongziliang committed
577 578 579 580 581 582
		if (!pSockRtp) {
			//分配端口失败
			WarnL << "分配rtp端口失败";
			send_NotAcceptable();
			return false;
		}
583
		auto pSockRtcp = UDPServer::Instance().getSock(get_local_ip().data(),2*trackIdx + 1 ,pSockRtp->get_local_port() + 1);
xiongziliang committed
584
		if (!pSockRtcp) {
xzl committed
585
			//分配端口失败
xiongziliang committed
586
			WarnL << "分配rtcp端口失败";
xzl committed
587 588 589
			send_NotAcceptable();
			return false;
		}
xiongziliang committed
590 591
		m_apUdpSock[trackIdx] = pSockRtp;
		//设置客户端内网端口信息
xzl committed
592 593 594 595 596
		string strClientPort = FindField(m_parser["Transport"].data(), "client_port=", NULL);
		uint16_t ui16PeerPort = atoi( FindField(strClientPort.data(), NULL, "-").data());
		struct sockaddr_in peerAddr;
		peerAddr.sin_family = AF_INET;
		peerAddr.sin_port = htons(ui16PeerPort);
597
		peerAddr.sin_addr.s_addr = inet_addr(get_peer_ip().data());
xzl committed
598 599
		bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero);
		m_apPeerUdpAddr[trackIdx].reset((struct sockaddr *) (new struct sockaddr_in(peerAddr)));
xiongziliang committed
600 601
		//尝试获取客户端nat映射地址
		startListenPeerUdpData();
xzl committed
602 603 604 605 606 607 608 609
		//InfoL << "分配端口:" << srv_port;
		int n = sprintf(m_pcBuf, "RTSP/1.0 200 OK\r\n"
				"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",
610
				m_iCseq, SERVER_NAME,
xzl committed
611 612
				RTSP_VERSION, RTSP_BUILDTIME,
				dateHeader().data(), strClientPort.data(),
xiongziliang committed
613
				pSockRtp->get_local_port(), pSockRtcp->get_local_port(),
xzl committed
614 615
				printSSRC(trackRef.ssrc).data(),
				m_strSession.data());
616
		SocketHelper::send(m_pcBuf, n);
xzl committed
617 618 619 620
	}
		break;
	case PlayerBase::RTP_MULTICAST: {
		if(!m_pBrdcaster){
621
			m_pBrdcaster = RtpBroadCaster::get(get_local_ip(),m_mediaInfo.m_vhost, m_mediaInfo.m_app, m_mediaInfo.m_streamid);
xzl committed
622 623 624 625 626 627 628 629 630 631 632 633 634
			if (!m_pBrdcaster) {
				send_NotAcceptable();
				return false;
			}
			weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
			m_pBrdcaster->setDetachCB(this, [weakSelf]() {
				auto strongSelf = weakSelf.lock();
				if(!strongSelf) {
					return;
				}
				strongSelf->safeShutdown();
			});
		}
xiongziliang committed
635
		int iSrvPort = m_pBrdcaster->getPort(trackRef.type);
xiongziliang committed
636
		//我们用trackIdx区分rtp和rtcp包
637
		auto pSockRtcp = UDPServer::Instance().getSock(get_local_ip().data(),2*trackIdx + 1,iSrvPort + 1);
xiongziliang committed
638 639 640 641 642 643 644
		if (!pSockRtcp) {
			//分配端口失败
			WarnL << "分配rtcp端口失败";
			send_NotAcceptable();
			return false;
		}
		startListenPeerUdpData();
645 646
        GET_CONFIG_AND_REGISTER(uint32_t,udpTTL,MultiCast::kUdpTTL);
        int n = sprintf(m_pcBuf, "RTSP/1.0 200 OK\r\n"
xzl committed
647 648 649 650 651 652
				"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",
653
				m_iCseq, SERVER_NAME,
xzl committed
654 655
				RTSP_VERSION, RTSP_BUILDTIME,
				dateHeader().data(), m_pBrdcaster->getIP().data(),
656
				get_local_ip().data(), iSrvPort, pSockRtcp->get_local_port(),
xzl committed
657 658
				udpTTL,printSSRC(trackRef.ssrc).data(),
				m_strSession.data());
659
		SocketHelper::send(m_pcBuf, n);
xzl committed
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676
	}
		break;
	default:
		break;
	}
	return true;
}

bool RtspSession::handleReq_Play() {
	if (m_uiTrackCnt == 0) {
		//还没有Describe
		return false;
	}
	if (m_parser["Session"] != m_strSession) {
		send_SessionNotFound();
		return false;
	}
677 678
	auto strRange = m_parser["Range"];
    auto onRes = [this,strRange](const string &err){
679
        bool authSuccess = err.empty();
680 681 682 683 684 685 686 687
        char response[2 * 1024];
        m_pcBuf = response;
        if(!authSuccess && m_bFirstPlay){
            //第一次play是播放,否则是恢复播放。只对播放鉴权
            int n = sprintf(m_pcBuf,
                            "RTSP/1.0 401 Unauthorized\r\n"
                            "CSeq: %d\r\n"
                            "Server: %s-%0.2f(build in %s)\r\n"
688 689 690 691 692 693
                            "%s"
                            "Content-Type: text/plain\r\n"
                            "Content-Length: %d\r\n\r\n%s",
                            m_iCseq, SERVER_NAME,
                            RTSP_VERSION, RTSP_BUILDTIME,
                            dateHeader().data(),(int)err.size(),err.data());
694
			SocketHelper::send(m_pcBuf,n);
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715
            shutdown();
            return;
        }
        if(m_pRtpReader){
            weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
            SockUtil::setNoDelay(m_pSender->rawFD(), false);
            m_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;
                    }
                    strongSelf->sendRtpPacket(pack);
                });

            });
        }
xzl committed
716

717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737
        auto pMediaSrc = m_pMediaSrc.lock();
        uint32_t iStamp = 0;
        if(pMediaSrc){
            if (strRange.size() && !m_bFirstPlay) {
                auto strStart = FindField(strRange.data(), "npt=", "-");
                if (strStart == "now") {
                    strStart = "0";
                }
                auto iStartTime = atof(strStart.data());
                InfoL << "rtsp seekTo:" << iStartTime;
                pMediaSrc->seekTo(iStartTime * 1000);
                iStamp = pMediaSrc->getStamp();
            }else if(pMediaSrc->getRing()->readerCount() == 1){
                //第一个消费者
                pMediaSrc->seekTo(0);
                iStamp = 0;
            }else{
                iStamp = pMediaSrc->getStamp();
            }
            for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
                auto &track = m_aTrackInfo[i];
xiongziliang committed
738 739 740
                track.ssrc = pMediaSrc->getSsrc(track.type);
                track.seq = pMediaSrc->getSeqence(track.type);
                track.timeStamp = pMediaSrc->getTimestamp(track.type);
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
            }
        }
        m_bFirstPlay = false;
        int iLen = sprintf(m_pcBuf, "RTSP/1.0 200 OK\r\n"
                                   "CSeq: %d\r\n"
                                   "Server: %s-%0.2f(build in %s)\r\n"
                                   "%s"
                                   "Session: %s\r\n"
                                   "Range: npt=%.2f-\r\n"
                                   "RTP-Info: ", m_iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
                           dateHeader().data(), m_strSession.data(),iStamp/1000.0);

        for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
            auto &track = m_aTrackInfo[i];
            if (track.inited == false) {
                //还有track没有setup
                shutdown();
                return;
            }
760 761
            iLen += sprintf(m_pcBuf + iLen, "url=%s/%s;seq=%d;rtptime=%u,",
                            m_strUrl.data(), track.controlSuffix.data(), track.seq,track.timeStamp);
762 763 764 765
        }
        iLen -= 1;
        (m_pcBuf)[iLen] = '\0';
        iLen += sprintf(m_pcBuf + iLen, "\r\n\r\n");
766 767 768 769 770
		SocketHelper::send(m_pcBuf, iLen);

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

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

bool RtspSession::handleReq_Pause() {
	if (m_parser["Session"] != m_strSession) {
		send_SessionNotFound();
		return false;
	}
	int n = sprintf(m_pcBuf, "RTSP/1.0 200 OK\r\n"
			"CSeq: %d\r\n"
			"Server: %s-%0.2f(build in %s)\r\n"
			"%s"
804
			"Session: %s\r\n\r\n", m_iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
xzl committed
805
			dateHeader().data(), m_strSession.data());
806
	SocketHelper::send(m_pcBuf, n);
xzl committed
807 808 809 810 811 812 813 814 815 816 817 818
	if(m_pRtpReader){
		m_pRtpReader->setReadCB(nullptr);
	}
	return true;

}

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

822
	SocketHelper::send(m_pcBuf, n);
xzl committed
823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
	TraceL << "播放器断开连接!";
	return false;
}

bool RtspSession::handleReq_Get() {
	m_strSessionCookie = m_parser["x-sessioncookie"];
	int n = sprintf(m_pcBuf, "HTTP/1.0 200 OK\r\n"
			"%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);
	g_mapGetter[m_strSessionCookie] = dynamic_pointer_cast<RtspSession>(shared_from_this());
xiongziliang committed
839
	//InfoL << m_strSessionCookie;
840
	SocketHelper::send(m_pcBuf, n);
xzl committed
841 842 843 844 845 846 847 848 849 850
	return true;

}

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

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

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

}
889

xzl committed
890
inline bool RtspSession::findStream() {
891 892
	RtspMediaSource::Ptr pMediaSrc =
    dynamic_pointer_cast<RtspMediaSource>( MediaSource::find(RTSP_SCHEMA,m_mediaInfo.m_vhost, m_mediaInfo.m_app,m_mediaInfo.m_streamid) );
xzl committed
893
	if (!pMediaSrc) {
894
		WarnL << "No such stream:" <<  m_mediaInfo.m_vhost << " " <<  m_mediaInfo.m_app << " " << m_mediaInfo.m_streamid;
xzl committed
895 896 897 898 899 900 901 902 903 904 905 906 907 908
		return false;
	}
	m_strSdp = pMediaSrc->getSdp();
	m_pWeakRing = pMediaSrc->getRing();

	m_uiTrackCnt = parserSDP(m_strSdp, m_aTrackInfo);
	if (m_uiTrackCnt == 0 || m_uiTrackCnt > 2) {
		return false;
	}
	m_strSession = makeRandStr(12);
	m_pMediaSrc = pMediaSrc;

	for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
		auto &track = m_aTrackInfo[i];
xiongziliang committed
909 910 911
		track.ssrc = pMediaSrc->getSsrc(track.type);
		track.seq = pMediaSrc->getSeqence(track.type);
		track.timeStamp = pMediaSrc->getTimestamp(track.type);
xzl committed
912 913 914 915 916
	}

	return true;
}

917 918

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

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


xiongziliang committed
990 991
inline void RtspSession::startListenPeerUdpData() {
	m_bListenPeerUdpData = true;
xzl committed
992
	weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
993 994
	UDPServer::Instance().listenPeer(get_peer_ip().data(), this,
			[weakSelf](int iTrackIdx,const Buffer::Ptr &pBuf,struct sockaddr *pPeerAddr)->bool {
xzl committed
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
				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) {
1012
	m_pSender = session->_sock;
xzl committed
1013 1014 1015
	weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
	session->m_onDestory = [weakSelf]() {
		auto strongSelf=weakSelf.lock();
xiongziliang committed
1016 1017 1018 1019 1020
        if(!strongSelf) {
            return;
        }
        //DebugL;
        strongSelf->m_pSender->setOnErr([weakSelf](const SockException &err) {
xzl committed
1021 1022 1023 1024 1025 1026 1027
			auto strongSelf=weakSelf.lock();
			if(!strongSelf) {
				return;
			}
			strongSelf->safeShutdown();
		});
	};
xiongziliang committed
1028
	session->shutdown_l(false);
xzl committed
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 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 1093 1094
}

#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;
	for (uint8_t i = 0; i < m_uiTrackCnt; i++) {
		auto &track = m_aTrackInfo[i];
		auto &counter = m_aRtcpCnt[i];

		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

}
/* namespace Session */
} /* namespace ZL */