RtspSession.cpp 34.6 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;
	}
514
	RtspTrack &trackRef = _aTrackInfo[trackIdx];
xzl committed
515 516 517 518 519 520
	if (trackRef.inited) {
		//已经初始化过该Track
		return false;
	}
	trackRef.inited = true; //现在初始化

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,
xiongziliang committed
565 566
				dateHeader().data(), trackRef.type * 2,
                trackRef.type * 2 + 1,
xzl committed
567
				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(),
xzl committed
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(),
xzl committed
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() {
667
	if (_uiTrackCnt == 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 723 724 725 726 727 728 729 730 731 732 733
                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();
            }
734 735
            for (unsigned int i = 0; i < _uiTrackCnt; i++) {
                auto &track = _aTrackInfo[i];
xiongziliang committed
736 737 738
                track.ssrc = pMediaSrc->getSsrc(track.type);
                track.seq = pMediaSrc->getSeqence(track.type);
                track.timeStamp = 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

751 752
        for (unsigned int i = 0; i < _uiTrackCnt; i++) {
            auto &track = _aTrackInfo[i];
753 754 755 756 757
            if (track.inited == false) {
                //还有track没有setup
                shutdown();
                return;
            }
758 759
            iLen += sprintf(_pcBuf + iLen, "url=%s/%s;seq=%d;rtptime=%u,",
                            _strUrl.data(), track.controlSuffix.data(), track.seq,track.timeStamp);
760 761
        }
        iLen -= 1;
762 763 764
        (_pcBuf)[iLen] = '\0';
        iLen += sprintf(_pcBuf + iLen, "\r\n\r\n");
		SocketHelper::send(_pcBuf, iLen);
765 766 767

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

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

bool RtspSession::handleReq_Pause() {
794
	if (_parser["Session"] != _strSession) {
xzl committed
795 796 797
		send_SessionNotFound();
		return false;
	}
798
	int n = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
xzl committed
799 800 801
			"CSeq: %d\r\n"
			"Server: %s-%0.2f(build in %s)\r\n"
			"%s"
802 803 804 805 806
			"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
807 808 809 810 811 812
	}
	return true;

}

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

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

bool RtspSession::handleReq_Get() {
826 827
	_strSessionCookie = _parser["x-sessioncookie"];
	int n = sprintf(_pcBuf, "HTTP/1.0 200 OK\r\n"
xzl committed
828 829 830 831 832 833 834 835
			"%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);
836 837 838
	g_mapGetter[_strSessionCookie] = dynamic_pointer_cast<RtspSession>(shared_from_this());
	//InfoL << _strSessionCookie;
	SocketHelper::send(_pcBuf, n);
xzl committed
839 840 841 842 843 844
	return true;

}

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

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

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

}
887

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

898 899
	_uiTrackCnt = parserSDP(_strSdp, _aTrackInfo);
	if (_uiTrackCnt == 0 || _uiTrackCnt > 2) {
xzl committed
900 901
		return false;
	}
902 903
	_strSession = makeRandStr(12);
	_pMediaSrc = pMediaSrc;
xzl committed
904

905 906
	for (unsigned int i = 0; i < _uiTrackCnt; i++) {
		auto &track = _aTrackInfo[i];
xiongziliang committed
907 908 909
		track.ssrc = pMediaSrc->getSsrc(track.type);
		track.seq = pMediaSrc->getSeqence(track.type);
		track.timeStamp = pMediaSrc->getTimestamp(track.type);
xzl committed
910 911 912 913 914
	}

	return true;
}

915 916

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

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


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

#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;
1034 1035 1036
	for (uint8_t i = 0; i < _uiTrackCnt; i++) {
		auto &track = _aTrackInfo[i];
		auto &counter = _aRtcpCnt[i];
xzl committed
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

		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
1090
/* namespace mediakit */
xzl committed
1091