RtspPlayer.cpp 19.8 KB
Newer Older
xiongziliang committed
1
/*
xiongziliang committed
2 3 4
 * MIT License
 *
 * Copyright (c) 2016 xiongziliang <771730766@qq.com>
5
 * Copyright (c) 2018 huohuo <913481084@qq.com>
xiongziliang committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * 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
27 28 29 30
#include <set>
#include <cmath>
#include <stdarg.h>
#include <algorithm>
xiongziliang committed
31
#include <iomanip>
xzl committed
32

xiongziliang committed
33
#include "Common/config.h"
xiongzilaing committed
34
#include "RtspPlayer.h"
xzl committed
35
#include "H264/SPSParser.h"
36
#include "Util/MD5.h"
xiongzilaing committed
37
#include "Util/mini.h"
38
#include "Util/util.h"
xiongziliang committed
39
#include "Util/base64.h"
xzl committed
40
#include "Network/sockutil.h"
xiongziliang committed
41
using namespace toolkit;
xzl committed
42

xiongziliang committed
43
namespace mediakit {
xzl committed
44 45

RtspPlayer::RtspPlayer(void){
xiongziliang committed
46
	RtpReceiver::setPoolSize(64);
xzl committed
47 48 49 50 51 52
}
RtspPlayer::~RtspPlayer(void) {
    DebugL<<endl;
}
void RtspPlayer::teardown(){
	if (alive()) {
53
		sendRtspRequest("TEARDOWN" ,_strContentBase);
xzl committed
54 55
		shutdown();
	}
56

xiongziliang committed
57 58
	_rtspMd5Nonce.clear();
	_rtspRealm.clear();
xiongziliang committed
59

xiongziliang committed
60
	_aTrackInfo.clear();
61 62
    _strSession.clear();
    _strContentBase.clear();
xiongziliang committed
63 64
	RtpReceiver::clear();

65 66 67 68 69
    CLEAR_ARR(_apUdpSock);
    CLEAR_ARR(_aui16FirstSeq)
    CLEAR_ARR(_aui64RtpRecv)
    CLEAR_ARR(_aui64RtpRecv)
    CLEAR_ARR(_aui16NowSeq)
xiongziliang committed
70 71
	CLEAR_ARR(_aiFistStamp);
	CLEAR_ARR(_aiNowStamp);
72 73 74 75

    _pBeatTimer.reset();
    _pPlayTimer.reset();
    _pRtpTimer.reset();
76
    _iSeekTo = 0;
xiongziliang committed
77 78
	_uiCseq = 1;
	_onHandshake = nullptr;
xzl committed
79
}
xiongziliang committed
80

xiongziliang committed
81 82 83
void RtspPlayer::play(const string &strUrl){
	auto userAndPwd = FindField(strUrl.data(),"://","@");
	Rtsp::eRtpType eType = (Rtsp::eRtpType)(int)(*this)[kRtpType];
xiongziliang committed
84
	if(userAndPwd.empty()){
xiongziliang committed
85
		play(strUrl,"","",eType);
xiongziliang committed
86 87
		return;
	}
xiongziliang committed
88
	auto suffix = FindField(strUrl.data(),"@",nullptr);
xiongziliang committed
89 90
	auto url = StrPrinter << "rtsp://" << suffix << endl;
	if(userAndPwd.find(":") == string::npos){
xiongziliang committed
91
		play(url,userAndPwd,"",eType);
xiongziliang committed
92 93 94 95
		return;
	}
	auto user = FindField(userAndPwd.data(),nullptr,":");
	auto pwd = FindField(userAndPwd.data(),":",nullptr);
xiongziliang committed
96
	play(url,user,pwd,eType);
xiongziliang committed
97
}
xzl committed
98
//播放,指定是否走rtp over tcp
xiongziliang committed
99
void RtspPlayer::play(const string &strUrl, const string &strUser, const string &strPwd,  Rtsp::eRtpType eType ) {
xiongziliang committed
100
	DebugL   << strUrl << " "
xiongziliang committed
101 102
			<< (strUser.size() ? strUser : "null") << " "
			<< (strPwd.size() ? strPwd:"null") << " "
xiongziliang committed
103
			<< eType;
xzl committed
104
	teardown();
105

xiongziliang committed
106
	if(strUser.size()){
107 108
        (*this)[kRtspUser] = strUser;
    }
xiongziliang committed
109
    if(strPwd.size()){
110 111
        (*this)[kRtspPwd] = strPwd;
		(*this)[kRtspPwdIsMD5] = false;
xzl committed
112
    }
113

114
	_eType = eType;
115

xiongziliang committed
116
	auto ip = FindField(strUrl.data(), "://", "/");
xzl committed
117
	if (!ip.size()) {
xiongziliang committed
118
		ip = FindField(strUrl.data(), "://", NULL);
xzl committed
119
	}
xiongziliang committed
120
	auto port = atoi(FindField(ip.data(), ":", NULL).data());
xzl committed
121 122 123 124 125
	if (port <= 0) {
		//rtsp 默认端口554
		port = 554;
	} else {
		//服务器域名
xiongziliang committed
126
		ip = FindField(ip.data(), NULL, ":");
xzl committed
127 128
	}

129
	_strUrl = strUrl;
xzl committed
130 131

	weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this());
132 133
	float playTimeOutSec = (*this)[kPlayTimeoutMS].as<int>() / 1000.0;
	_pPlayTimer.reset( new Timer(playTimeOutSec,  [weakSelf]() {
xzl committed
134 135 136 137
		auto strongSelf=weakSelf.lock();
		if(!strongSelf) {
			return false;
		}
138
		strongSelf->onPlayResult_l(SockException(Err_timeout,"play rtsp timeout"));
xzl committed
139 140
		strongSelf->teardown();
		return false;
141
	},getPoller()));
142

xiongziliang committed
143 144 145 146
	if(!(*this)[PlayerBase::kNetAdapter].empty()){
		setNetAdapter((*this)[PlayerBase::kNetAdapter]);
	}
	startConnect(ip, port , playTimeOutSec);
147 148 149 150 151 152 153 154 155
}
void RtspPlayer::onConnect(const SockException &err){
	if(err.getErrCode()!=Err_success) {
		onPlayResult_l(err);
		teardown();
		return;
	}

	sendDescribe();
xzl committed
156 157
}

158
void RtspPlayer::onRecv(const Buffer::Ptr& pBuf) {
159
    input(pBuf->data(),pBuf->size());
xzl committed
160 161
}
void RtspPlayer::onErr(const SockException &ex) {
162
	onShutdown_l (ex);
xzl committed
163
}
164 165
// from live555
bool RtspPlayer::handleAuthenticationFailure(const string &paramsStr) {
xiongziliang committed
166
    if(!_rtspRealm.empty()){
167 168 169 170
        //已经认证过了
        return false;
    }

xiongziliang committed
171 172 173 174 175 176 177 178
    char *realm = new char[paramsStr.size()];
    char *nonce = new char[paramsStr.size()];
    char *stale = new char[paramsStr.size()];
    onceToken token(nullptr,[&](){
        delete[] realm;
        delete[] nonce;
        delete[] stale;
    });
179 180

    if (sscanf(paramsStr.data(), "Digest realm=\"%[^\"]\", nonce=\"%[^\"]\", stale=%[a-zA-Z]", realm, nonce, stale) == 3) {
xiongziliang committed
181 182
        _rtspRealm = (const char *)realm;
        _rtspMd5Nonce = (const char *)nonce;
183 184 185
        return true;
    }
    if (sscanf(paramsStr.data(), "Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"", realm, nonce) == 2) {
xiongziliang committed
186 187
        _rtspRealm = (const char *)realm;
        _rtspMd5Nonce = (const char *)nonce;
188 189 190
        return true;
    }
    if (sscanf(paramsStr.data(), "Basic realm=\"%[^\"]\"", realm) == 1) {
xiongziliang committed
191
        _rtspRealm = (const char *)realm;
192 193 194 195 196 197
        return true;
    }
    return false;
}
void RtspPlayer::handleResDESCRIBE(const Parser& parser) {
	string authInfo = parser["WWW-Authenticate"];
xzl committed
198
	//发送DESCRIBE命令后的回复
199 200 201 202
	if ((parser.Url() == "401") && handleAuthenticationFailure(authInfo)) {
		sendDescribe();
		return;
	}
203 204 205 206 207
	if(parser.Url() == "302"){
		auto newUrl = parser["Location"];
		if(newUrl.empty()){
			throw std::runtime_error("未找到Location字段(跳转url)");
		}
xiongziliang committed
208
		play(newUrl);
209 210
		return;
	}
xzl committed
211 212 213 214
	if (parser.Url() != "200") {
		throw std::runtime_error(
		StrPrinter << "DESCRIBE:" << parser.Url() << " " << parser.Tail() << endl);
	}
215
	_strContentBase = parser["Content-Base"];
216

217 218
    if(_strContentBase.empty()){
        _strContentBase = _strUrl;
219
    }
220 221
    if (_strContentBase.back() == '/') {
        _strContentBase.pop_back();
222 223
    }

xzl committed
224
	//解析sdp
225
	_sdpAttr.load(parser.Content());
xiongziliang committed
226 227 228
	_aTrackInfo = _sdpAttr.getAvailableTrack();

	if (_aTrackInfo.empty()) {
xiongziliang committed
229
		throw std::runtime_error("无有效的Sdp Track");
xzl committed
230
	}
231
	if (!onCheckSDP(parser.Content(), _sdpAttr)) {
xzl committed
232 233
		throw std::runtime_error("onCheckSDP faied");
	}
xiongziliang committed
234

xzl committed
235 236 237
	sendSetup(0);
}
//发送SETUP命令
238
bool RtspPlayer::sendSetup(unsigned int trackIndex) {
239
    _onHandshake = std::bind(&RtspPlayer::handleResSETUP,this, placeholders::_1,trackIndex);
240

241
    auto &track = _aTrackInfo[trackIndex];
xiongziliang committed
242
	auto baseUrl = _strContentBase + "/" + track->_control_surffix;
243
	switch (_eType) {
xiongziliang committed
244
		case Rtsp::RTP_TCP: {
xiongziliang committed
245
			return sendRtspRequest("SETUP",baseUrl,{"Transport",StrPrinter << "RTP/AVP/TCP;unicast;interleaved=" << track->_type * 2 << "-" << track->_type * 2 + 1});
xzl committed
246
		}
xiongziliang committed
247
		case Rtsp::RTP_MULTICAST: {
xiongziliang committed
248
			return sendRtspRequest("SETUP",baseUrl,{"Transport","Transport: RTP/AVP;multicast"});
249
		}
xiongziliang committed
250
		case Rtsp::RTP_UDP: {
251 252 253
			_apUdpSock[trackIndex].reset(new Socket());
			if (!_apUdpSock[trackIndex]->bindUdpSock(0, get_local_ip().data())) {
				_apUdpSock[trackIndex].reset();
254 255
				throw std::runtime_error("open udp sock err");
			}
256
			int port = _apUdpSock[trackIndex]->get_local_port();
xiongziliang committed
257
			return sendRtspRequest("SETUP",baseUrl,{"Transport",StrPrinter << "RTP/AVP;unicast;client_port=" << port << "-" << port + 1});
258 259 260
		}
		default:
			return false;
xzl committed
261 262 263
	}
}

264
void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int uiTrackIndex) {
xzl committed
265 266 267 268 269
	if (parser.Url() != "200") {
		throw std::runtime_error(
		StrPrinter << "SETUP:" << parser.Url() << " " << parser.Tail() << endl);
	}
	if (uiTrackIndex == 0) {
270 271 272
		_strSession = parser["Session"];
        _strSession.append(";");
        _strSession = FindField(_strSession.data(), nullptr, ";");
xzl committed
273 274 275 276
	}

	auto strTransport = parser["Transport"];
	if(strTransport.find("TCP") != string::npos){
xiongziliang committed
277
		_eType = Rtsp::RTP_TCP;
xzl committed
278
	}else if(strTransport.find("multicast") != string::npos){
xiongziliang committed
279
		_eType = Rtsp::RTP_MULTICAST;
xzl committed
280
	}else{
xiongziliang committed
281
		_eType = Rtsp::RTP_UDP;
xzl committed
282 283
	}

xiongziliang committed
284
	RtspSplitter::enableRecvRtp(_eType == Rtsp::RTP_TCP);
285

xiongziliang committed
286 287 288
	if(_eType == Rtsp::RTP_TCP)  {
		string interleaved = FindField( FindField((strTransport + ";").data(), "interleaved=", ";").data(), NULL, "-");
		_aTrackInfo[uiTrackIndex]->_interleaved = atoi(interleaved.data());
xzl committed
289
	}else{
xiongziliang committed
290 291 292
		const char *strPos = (_eType == Rtsp::RTP_MULTICAST ? "port=" : "server_port=") ;
		auto port_str = FindField((strTransport + ";").data(), strPos, ";");
		uint16_t port = atoi(FindField(port_str.data(), NULL, "-").data());
293
        auto &pUdpSockRef = _apUdpSock[uiTrackIndex];
xzl committed
294 295 296
        if(!pUdpSockRef){
            pUdpSockRef.reset(new Socket());
        }
xiongziliang committed
297

xiongziliang committed
298 299
		if (_eType == Rtsp::RTP_MULTICAST) {
			auto multiAddr = FindField((strTransport + ";").data(), "destination=", ";");
xzl committed
300 301 302 303 304 305 306 307 308 309 310 311
			if (!pUdpSockRef->bindUdpSock(port, "0.0.0.0")) {
				pUdpSockRef.reset();
				throw std::runtime_error("open udp sock err");
			}
			auto fd = pUdpSockRef->rawFD();
			if (-1 == SockUtil::joinMultiAddrFilter(fd, multiAddr.data(), get_peer_ip().data(),get_local_ip().data())) {
				SockUtil::joinMultiAddr(fd, multiAddr.data(),get_local_ip().data());
			}
		} else {
			struct sockaddr_in rtpto;
			rtpto.sin_port = ntohs(port);
			rtpto.sin_family = AF_INET;
xiongziliang committed
312
			rtpto.sin_addr.s_addr = inet_addr(get_peer_ip().data());
313 314
			pUdpSockRef->setSendPeerAddr((struct sockaddr *)&(rtpto));
			pUdpSockRef->send("\xce\xfa\xed\xfe", 4);
xzl committed
315 316 317
		}
	}

xiongziliang committed
318
	if (uiTrackIndex < _aTrackInfo.size() - 1) {
xzl committed
319 320 321 322 323
		//需要继续发送SETUP命令
		sendSetup(uiTrackIndex + 1);
		return;
	}

xiongziliang committed
324
	for (unsigned int i = 0; i < _aTrackInfo.size() && _eType != Rtsp::RTP_TCP; i++) {
325
		auto &pUdpSockRef = _apUdpSock[i];
xzl committed
326 327 328 329 330
		if(!pUdpSockRef){
			continue;
		}
		auto srcIP = inet_addr(get_peer_ip().data());
		weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this());
331
		pUdpSockRef->setOnRead([srcIP,i,weakSelf](const Buffer::Ptr &buf, struct sockaddr *addr) {
xzl committed
332 333 334 335 336
			auto strongSelf=weakSelf.lock();
			if(!strongSelf) {
				return;
			}
			if(((struct sockaddr_in *)addr)->sin_addr.s_addr != srcIP) {
xiongziliang committed
337
				WarnL << "收到其他地址的UDP数据:" << inet_ntoa(((struct sockaddr_in *) addr)->sin_addr);
xzl committed
338 339
				return;
			}
xiongziliang committed
340
			strongSelf->handleOneRtp(i,strongSelf->_aTrackInfo[i],(unsigned char *)buf->data(),buf->size());
xzl committed
341 342 343
		});
	}
	/////////////////////////心跳/////////////////////////////////
xiongziliang committed
344 345 346 347 348 349 350 351 352 353 354
	if(_eType != Rtsp::RTP_TCP){
		weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this());
		_pBeatTimer.reset(new Timer((*this)[kBeatIntervalMS].as<int>() / 1000.0, [weakSelf](){
			auto strongSelf = weakSelf.lock();
			if (!strongSelf){
				return false;
			}
			return strongSelf->sendOptions();
		},getPoller()));
	}

xzl committed
355 356 357 358
	pause(false);
}

bool RtspPlayer::sendOptions() {
359
	_onHandshake = [](const Parser& parser){
360
//		DebugL << "options response";
xzl committed
361
	};
362
	return sendRtspRequest("OPTIONS",_strContentBase);
xzl committed
363
}
364 365 366

bool RtspPlayer::sendDescribe() {
	//发送DESCRIBE命令后处理函数:handleResDESCRIBE
367
	_onHandshake = std::bind(&RtspPlayer::handleResDESCRIBE,this, placeholders::_1);
xiongziliang committed
368
	return sendRtspRequest("DESCRIBE",_strUrl,{"Accept","application/sdp"});
369 370 371
}


372
bool RtspPlayer::sendPause(bool bPause,uint32_t seekMS){
xzl committed
373 374
    if(!bPause){
        //修改时间轴
375
        int iTimeInc = seekMS - getProgressMilliSecond();
xiongziliang committed
376
        for(unsigned int i = 0 ;i < _aTrackInfo.size() ;i++){
377 378
			_aiFistStamp[i] = _aiNowStamp[i] + iTimeInc;
            _aiNowStamp[i] = _aiFistStamp[i];
xzl committed
379
        }
380
        _iSeekTo = seekMS;
xzl committed
381
    }
382 383

	//开启或暂停rtsp
384
	_onHandshake = std::bind(&RtspPlayer::handleResPAUSE,this, placeholders::_1,bPause);
xiongziliang committed
385 386 387
	return sendRtspRequest(bPause ? "PAUSE" : "PLAY",
						   _strContentBase,
						   {"Range",StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << seekMS / 1000.0 << "-"});
xzl committed
388 389
}
void RtspPlayer::pause(bool bPause) {
390
    sendPause(bPause, getProgressMilliSecond());
xzl committed
391 392
}

393
void RtspPlayer::handleResPAUSE(const Parser& parser, bool bPause) {
xzl committed
394 395 396 397 398 399 400 401 402 403 404 405
	if (parser.Url() != "200") {
		WarnL <<(bPause ? "Pause" : "Play") << " failed:" << parser.Url() << " " << parser.Tail() << endl;
		return;
	}
	if (!bPause) {
        //修正时间轴
        auto strRange = parser["Range"];
        if (strRange.size()) {
            auto strStart = FindField(strRange.data(), "npt=", "-");
            if (strStart == "now") {
                strStart = "0";
            }
406 407
            _iSeekTo = 1000 * atof(strStart.data());
            DebugL << "seekTo(ms):" << _iSeekTo ;
xzl committed
408 409 410 411
        }
        auto strRtpInfo =  parser["RTP-Info"];
        if (strRtpInfo.size()) {
            strRtpInfo.append(",");
412
            vector<string> vec = split(strRtpInfo, ",");
xzl committed
413
            for(auto &strTrack : vec){
414
                strTrack.append(";");
xiongziliang committed
415
                auto strControlSuffix = strTrack.substr(1 + strTrack.rfind('/'),strTrack.find(';') - strTrack.rfind('/') - 1);
416
                auto strRtpTime = FindField(strTrack.data(), "rtptime=", ";");
417
                auto idx = getTrackIndexByControlSuffix(strControlSuffix);
418 419 420 421 422
                if(idx != -1){
                    _aiFistStamp[idx] = atoll(strRtpTime.data()) * 1000 / _aTrackInfo[idx]->_samplerate;
                    _aiNowStamp[idx] = _aiFistStamp[idx];
                    DebugL << "rtptime(ms):" << strControlSuffix <<" " << strRtpTime;
                }
xzl committed
423 424
            }
        }
425
		onPlayResult_l(SockException(Err_success, "rtsp play success"));
xzl committed
426
	} else {
427
		_pRtpTimer.reset();
xzl committed
428 429 430
	}
}

431 432 433 434 435 436 437 438 439 440 441 442 443
void RtspPlayer::onWholeRtspPacket(Parser &parser) {
    try {
		decltype(_onHandshake) fun;
		_onHandshake.swap(fun);
        if(fun){
            fun(parser);
        }
        parser.Clear();
    } catch (std::exception &err) {
        SockException ex(Err_other, err.what());
        onPlayResult_l(ex);
        onShutdown_l(ex);
        teardown();
xzl committed
444 445 446
    }
}

447 448 449 450 451 452 453 454 455 456 457
void RtspPlayer::onRtpPacket(const char *data, uint64_t len) {
    if(len > 1600){
        //没有大于MTU的包
        return;
    }
    int trackIdx = -1;
    uint8_t interleaved = data[1];
    if(interleaved %2 ==0){
        trackIdx = getTrackIndexByInterleaved(interleaved);
    }
    if (trackIdx != -1) {
xiongziliang committed
458
        handleOneRtp(trackIdx,_aTrackInfo[trackIdx],(unsigned char *)data + 4, len - 4);
459
    }
xzl committed
460 461 462
}


xiongziliang committed
463
void RtspPlayer::onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx){
xzl committed
464
	//统计丢包率
465 466 467
	if (_aui16FirstSeq[trackidx] == 0 || rtppt->sequence < _aui16FirstSeq[trackidx]) {
		_aui16FirstSeq[trackidx] = rtppt->sequence;
		_aui64RtpRecv[trackidx] = 0;
xzl committed
468
	}
469 470
	_aui64RtpRecv[trackidx] ++;
	_aui16NowSeq[trackidx] = rtppt->sequence;
471
	_aiNowStamp[trackidx] = rtppt->timeStamp;
472 473 474
	if( _aiFistStamp[trackidx] == 0){
		_aiFistStamp[trackidx] = _aiNowStamp[trackidx];
	}
475 476

    rtppt->timeStamp -= _aiFistStamp[trackidx];
477
	onRecvRTP_l(rtppt,_aTrackInfo[trackidx]);
xzl committed
478
}
479
float RtspPlayer::getPacketLossRate(TrackType type) const{
xiongziliang committed
480
	int iTrackIdx = getTrackIndexByTrackType(type);
xzl committed
481 482 483
	if(iTrackIdx == -1){
		uint64_t totalRecv = 0;
		uint64_t totalSend = 0;
xiongziliang committed
484
		for (unsigned int i = 0; i < _aTrackInfo.size(); i++) {
485 486
			totalRecv += _aui64RtpRecv[i];
			totalSend += (_aui16NowSeq[i] - _aui16FirstSeq[i] + 1);
xzl committed
487 488 489 490 491 492 493 494
		}
		if(totalSend == 0){
			return 0;
		}
		return 1.0 - (double)totalRecv / totalSend;
	}


495
	if(_aui16NowSeq[iTrackIdx] - _aui16FirstSeq[iTrackIdx] + 1 == 0){
xzl committed
496 497
		return 0;
	}
498
	return 1.0 - (double)_aui64RtpRecv[iTrackIdx] / (_aui16NowSeq[iTrackIdx] - _aui16FirstSeq[iTrackIdx] + 1);
xzl committed
499 500
}

501 502
uint32_t RtspPlayer::getProgressMilliSecond() const{
	uint32_t iTime[2] = {0,0};
xiongziliang committed
503
    for(unsigned int i = 0 ;i < _aTrackInfo.size() ;i++){
504
		iTime[i] = _aiNowStamp[i] - _aiFistStamp[i];
xzl committed
505
    }
506
    return _iSeekTo + MAX(iTime[0],iTime[1]);
xzl committed
507
}
508 509
void RtspPlayer::seekToMilliSecond(uint32_t ms) {
    sendPause(false,ms);
xzl committed
510
}
511

xiongziliang committed
512 513 514 515 516 517 518 519 520 521 522 523 524
bool RtspPlayer::sendRtspRequest(const string &cmd, const string &url, const std::initializer_list<string> &header) {
	string key;
	StrCaseMap header_map;
	int i = 0;
	for(auto &val : header){
		if(++i % 2 == 0){
			header_map.emplace(key,val);
		}else{
			key = val;
		}
	}
	return sendRtspRequest(cmd,url,header_map);
}
525 526
bool RtspPlayer::sendRtspRequest(const string &cmd, const string &url,const StrCaseMap &header_const) {
	auto header = header_const;
527
	header.emplace("CSeq",StrPrinter << _uiCseq++);
xiongziliang committed
528 529
	header.emplace("User-Agent",SERVER_NAME "(build in " __DATE__ " " __TIME__ ")");

530 531
	if(!_strSession.empty()){
		header.emplace("Session",_strSession);
532 533
	}

xiongziliang committed
534 535
	if(!_rtspRealm.empty() && !(*this)[PlayerBase::kRtspUser].empty()){
		if(!_rtspMd5Nonce.empty()){
536 537 538 539 540 541 542 543 544 545 546
			//MD5认证
			/*
			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) );
			 */
			string encrypted_pwd = (*this)[PlayerBase::kRtspPwd];
			if(!(*this)[PlayerBase::kRtspPwdIsMD5].as<bool>()){
xiongziliang committed
547
				encrypted_pwd = MD5((*this)[PlayerBase::kRtspUser]+ ":" + _rtspRealm + ":" + encrypted_pwd).hexdigest();
548
			}
xiongziliang committed
549
			auto response = MD5( encrypted_pwd + ":" + _rtspMd5Nonce  + ":" + MD5(cmd + ":" + url).hexdigest()).hexdigest();
550 551 552
			_StrPrinter printer;
			printer << "Digest ";
			printer << "username=\"" << (*this)[PlayerBase::kRtspUser] << "\", ";
xiongziliang committed
553 554
			printer << "realm=\"" << _rtspRealm << "\", ";
			printer << "nonce=\"" << _rtspMd5Nonce << "\", ";
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
			printer << "uri=\"" << url << "\", ";
			printer << "response=\"" << response << "\"";
			header.emplace("Authorization",printer);
		}else if(!(*this)[PlayerBase::kRtspPwdIsMD5].as<bool>()){
			//base64认证
			string authStr = StrPrinter << (*this)[PlayerBase::kRtspUser] << ":" << (*this)[PlayerBase::kRtspPwd];
			char authStrBase64[1024] = {0};
			av_base64_encode(authStrBase64,sizeof(authStrBase64),(uint8_t *)authStr.data(),authStr.size());
			header.emplace("Authorization",StrPrinter << "Basic " << authStrBase64 );
		}
	}

	_StrPrinter printer;
	printer << cmd << " " << url << " RTSP/1.0\r\n";
	for (auto &pr : header){
		printer << pr.first << ": " << pr.second << "\r\n";
	}
	return send(printer << "\r\n") > 0;
}


void RtspPlayer::onShutdown_l(const SockException &ex) {
	WarnL << ex.getErrCode() << " " << ex.what();
578 579 580
	_pPlayTimer.reset();
	_pRtpTimer.reset();
	_pBeatTimer.reset();
581 582
	onShutdown(ex);
}
xiongziliang committed
583
void RtspPlayer::onRecvRTP_l(const RtpPacket::Ptr &pRtppt, const SdpTrack::Ptr &track) {
584
	_rtpTicker.resetTime();
585 586 587 588
	onRecvRTP(pRtppt,track);
}
void RtspPlayer::onPlayResult_l(const SockException &ex) {
	WarnL << ex.getErrCode() << " " << ex.what();
589 590
	_pPlayTimer.reset();
	_pRtpTimer.reset();
591
	if (!ex) {
592
		_rtpTicker.resetTime();
593
		weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this());
594 595
		int timeoutMS = (*this)[kMediaTimeoutMS].as<int>();
		_pRtpTimer.reset( new Timer(timeoutMS / 2000.0, [weakSelf,timeoutMS]() {
596 597 598 599
			auto strongSelf=weakSelf.lock();
			if(!strongSelf) {
				return false;
			}
600
			if(strongSelf->_rtpTicker.elapsedTime()> timeoutMS) {
601 602 603 604 605 606
				//recv rtp timeout!
				strongSelf->onShutdown_l(SockException(Err_timeout,"recv rtp timeout"));
				strongSelf->teardown();
				return false;
			}
			return true;
607
		},getPoller()));
608 609 610 611
	}
	onPlayResult(ex);
}

xiongziliang committed
612
int RtspPlayer::getTrackIndexByControlSuffix(const string &controlSuffix) const{
xiongziliang committed
613
	for (unsigned int i = 0; i < _aTrackInfo.size(); i++) {
614 615
		auto pos = _aTrackInfo[i]->_control_surffix.find(controlSuffix);
		if (pos == 0) {
616 617 618 619 620
			return i;
		}
	}
	return -1;
}
xiongziliang committed
621
int RtspPlayer::getTrackIndexByInterleaved(int interleaved) const{
xiongziliang committed
622
	for (unsigned int i = 0; i < _aTrackInfo.size(); i++) {
623
		if (_aTrackInfo[i]->_interleaved == interleaved) {
xiongziliang committed
624 625 626 627 628 629 630
			return i;
		}
	}
	return -1;
}

int RtspPlayer::getTrackIndexByTrackType(TrackType trackType) const {
xiongziliang committed
631
	for (unsigned int i = 0; i < _aTrackInfo.size(); i++) {
632
		if (_aTrackInfo[i]->_type == trackType) {
633 634 635 636 637 638
			return i;
		}
	}
	return -1;
}

xiongziliang committed
639
} /* namespace mediakit */
xzl committed
640 641