RtspPlayer.cpp 27.1 KB
Newer Older
xiongziliang committed
1
/*
xiongziliang committed
2 3
 * MIT License
 *
xiongziliang committed
4
 * Copyright (c) 2016-2019 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"
35
#include "Util/MD5.h"
xiongzilaing committed
36
#include "Util/mini.h"
37
#include "Util/util.h"
xiongziliang committed
38
#include "Util/base64.h"
xzl committed
39
#include "Network/sockutil.h"
xiongziliang committed
40
using namespace toolkit;
xiongziliang committed
41
using namespace mediakit::Client;
xzl committed
42

xiongziliang committed
43
namespace mediakit {
xzl committed
44

45
RtspPlayer::RtspPlayer(const EventPoller::Ptr &poller) : TcpClient(poller){
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);
xiongziliang committed
54
		shutdown(SockException(Err_shutdown,"teardown"));
xzl committed
55
	}
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
    CLEAR_ARR(_apRtpSock);
    CLEAR_ARR(_apRtcpSock);
67 68 69 70
    CLEAR_ARR(_aui16FirstSeq)
    CLEAR_ARR(_aui64RtpRecv)
    CLEAR_ARR(_aui64RtpRecv)
    CLEAR_ARR(_aui16NowSeq)
xiongziliang committed
71 72
	CLEAR_ARR(_aiFistStamp);
	CLEAR_ARR(_aiNowStamp);
73 74 75

    _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());
xiongziliang committed
132
	float playTimeOutSec = (*this)[kTimeoutMS].as<int>() / 1000.0;
133
	_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
		return false;
140
	},getPoller()));
141

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

	sendDescribe();
xzl committed
154 155
}

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

xiongziliang committed
169 170 171 172 173 174 175 176
    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;
    });
177 178

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

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

xzl committed
222
	//解析sdp
xiongziliang committed
223 224
	_sdpParser.load(parser.Content());
	_aTrackInfo = _sdpParser.getAvailableTrack();
xiongziliang committed
225 226

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

xzl committed
233 234
	sendSetup(0);
}
235

xiongziliang committed
236
//有必要的情况下创建udp端口
237 238 239 240 241
void RtspPlayer::createUdpSockIfNecessary(int track_idx){
	auto &rtpSockRef = _apRtpSock[track_idx];
	auto &rtcpSockRef = _apRtcpSock[track_idx];
	if(!rtpSockRef){
		rtpSockRef.reset(new Socket(getPoller()));
xiongziliang committed
242
		//rtp随机端口
243 244 245 246 247 248 249 250
		if (!rtpSockRef->bindUdpSock(0, get_local_ip().data())) {
			rtpSockRef.reset();
			throw std::runtime_error("open rtp sock failed");
		}
	}

	if(!rtcpSockRef){
		rtcpSockRef.reset(new Socket(getPoller()));
xiongziliang committed
251
		//rtcp端口为rtp端口+1,目的是为了兼容某些服务器,其实更推荐随机端口
252 253 254 255 256 257 258 259
		if (!rtcpSockRef->bindUdpSock(rtpSockRef->get_local_port() + 1, get_local_ip().data())) {
			rtcpSockRef.reset();
			throw std::runtime_error("open rtcp sock failed");
		}
	}
}


xzl committed
260
//发送SETUP命令
261
void RtspPlayer::sendSetup(unsigned int trackIndex) {
262 263
    _onHandshake = std::bind(&RtspPlayer::handleResSETUP,this, placeholders::_1,trackIndex);
    auto &track = _aTrackInfo[trackIndex];
xiongziliang committed
264
	auto baseUrl = _strContentBase + "/" + track->_control_surffix;
265
	switch (_eType) {
xiongziliang committed
266
		case Rtsp::RTP_TCP: {
267
			sendRtspRequest("SETUP",baseUrl,{"Transport",StrPrinter << "RTP/AVP/TCP;unicast;interleaved=" << track->_type * 2 << "-" << track->_type * 2 + 1});
xzl committed
268
		}
269
			break;
xiongziliang committed
270
		case Rtsp::RTP_MULTICAST: {
271
			sendRtspRequest("SETUP",baseUrl,{"Transport","Transport: RTP/AVP;multicast"});
272
		}
273
			break;
xiongziliang committed
274
		case Rtsp::RTP_UDP: {
275
			createUdpSockIfNecessary(trackIndex);
276 277 278 279
			sendRtspRequest("SETUP",baseUrl,{"Transport",
                                    StrPrinter << "RTP/AVP;unicast;client_port="
                                    << _apRtpSock[trackIndex]->get_local_port() << "-"
                                    << _apRtcpSock[trackIndex]->get_local_port()});
280
		}
281
			break;
282
		default:
283
			break;
xzl committed
284 285 286
	}
}

287
void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int uiTrackIndex) {
xzl committed
288 289 290 291 292
	if (parser.Url() != "200") {
		throw std::runtime_error(
		StrPrinter << "SETUP:" << parser.Url() << " " << parser.Tail() << endl);
	}
	if (uiTrackIndex == 0) {
293 294 295
		_strSession = parser["Session"];
        _strSession.append(";");
        _strSession = FindField(_strSession.data(), nullptr, ";");
xzl committed
296 297 298
	}

	auto strTransport = parser["Transport"];
299
	if(strTransport.find("TCP") != string::npos || strTransport.find("interleaved") != string::npos){
xiongziliang committed
300
		_eType = Rtsp::RTP_TCP;
xzl committed
301
	}else if(strTransport.find("multicast") != string::npos){
xiongziliang committed
302
		_eType = Rtsp::RTP_MULTICAST;
xzl committed
303
	}else{
xiongziliang committed
304
		_eType = Rtsp::RTP_UDP;
xzl committed
305 306
	}

xiongziliang committed
307
	RtspSplitter::enableRecvRtp(_eType == Rtsp::RTP_TCP);
308

xiongziliang committed
309 310 311
	if(_eType == Rtsp::RTP_TCP)  {
		string interleaved = FindField( FindField((strTransport + ";").data(), "interleaved=", ";").data(), NULL, "-");
		_aTrackInfo[uiTrackIndex]->_interleaved = atoi(interleaved.data());
xzl committed
312
	}else{
xiongziliang committed
313 314
		const char *strPos = (_eType == Rtsp::RTP_MULTICAST ? "port=" : "server_port=") ;
		auto port_str = FindField((strTransport + ";").data(), strPos, ";");
315 316 317 318
		uint16_t rtp_port = atoi(FindField(port_str.data(), NULL, "-").data());
        uint16_t rtcp_port = atoi(FindField(port_str.data(), "-",NULL).data());
        auto &pRtpSockRef = _apRtpSock[uiTrackIndex];
        auto &pRtcpSockRef = _apRtcpSock[uiTrackIndex];
xiongziliang committed
319

xiongziliang committed
320
		if (_eType == Rtsp::RTP_MULTICAST) {
321
		    //udp组播
xiongziliang committed
322
			auto multiAddr = FindField((strTransport + ";").data(), "destination=", ";");
323
            pRtpSockRef.reset(new Socket(getPoller()));
324
			if (!pRtpSockRef->bindUdpSock(rtp_port, multiAddr.data())) {
325
				pRtpSockRef.reset();
xzl committed
326 327
				throw std::runtime_error("open udp sock err");
			}
328
			auto fd = pRtpSockRef->rawFD();
xzl committed
329 330 331 332
			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 {
333 334
			createUdpSockIfNecessary(uiTrackIndex);
			//udp单播
xzl committed
335
			struct sockaddr_in rtpto;
336
			rtpto.sin_port = ntohs(rtp_port);
xzl committed
337
			rtpto.sin_family = AF_INET;
xiongziliang committed
338
			rtpto.sin_addr.s_addr = inet_addr(get_peer_ip().data());
339 340 341 342 343 344 345 346 347
			pRtpSockRef->setSendPeerAddr((struct sockaddr *)&(rtpto));
			//发送rtp打洞包
			pRtpSockRef->send("\xce\xfa\xed\xfe", 4);

			//设置rtcp发送目标,为后续发送rtcp做准备
            rtpto.sin_port = ntohs(rtcp_port);
            rtpto.sin_family = AF_INET;
            rtpto.sin_addr.s_addr = inet_addr(get_peer_ip().data());
            pRtcpSockRef->setSendPeerAddr((struct sockaddr *)&(rtpto));
xzl committed
348
		}
349 350 351 352

        auto srcIP = inet_addr(get_peer_ip().data());
        weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this());
        //设置rtp over udp接收回调处理函数
353
        pRtpSockRef->setOnRead([srcIP, uiTrackIndex, weakSelf](const Buffer::Ptr &buf, struct sockaddr *addr , int addr_len) {
354 355 356 357 358 359 360 361 362 363 364 365 366
            auto strongSelf = weakSelf.lock();
            if (!strongSelf) {
                return;
            }
            if (((struct sockaddr_in *) addr)->sin_addr.s_addr != srcIP) {
                WarnL << "收到其他地址的rtp数据:" << inet_ntoa(((struct sockaddr_in *) addr)->sin_addr);
                return;
            }
            strongSelf->handleOneRtp(uiTrackIndex, strongSelf->_aTrackInfo[uiTrackIndex], (unsigned char *) buf->data(), buf->size());
        });

        if(pRtcpSockRef) {
            //设置rtcp over udp接收回调处理函数
367
            pRtcpSockRef->setOnRead([srcIP, uiTrackIndex, weakSelf](const Buffer::Ptr &buf, struct sockaddr *addr , int addr_len) {
368 369 370 371 372 373 374 375
                auto strongSelf = weakSelf.lock();
                if (!strongSelf) {
                    return;
                }
                if (((struct sockaddr_in *) addr)->sin_addr.s_addr != srcIP) {
                    WarnL << "收到其他地址的rtcp数据:" << inet_ntoa(((struct sockaddr_in *) addr)->sin_addr);
                    return;
                }
376 377
                strongSelf->onRtcpPacket(uiTrackIndex, strongSelf->_aTrackInfo[uiTrackIndex],
                                         (unsigned char *) buf->data(), buf->size());
378 379
            });
        }
xzl committed
380 381
	}

xiongziliang committed
382
	if (uiTrackIndex < _aTrackInfo.size() - 1) {
xzl committed
383 384 385 386
		//需要继续发送SETUP命令
		sendSetup(uiTrackIndex + 1);
		return;
	}
387 388
	//所有setup命令发送完毕
	//发送play命令
xzl committed
389 390 391
	pause(false);
}

392
void RtspPlayer::sendOptions() {
393
	_onHandshake = [](const Parser& parser){
394
//		DebugL << "options response";
xzl committed
395
	};
396
	sendRtspRequest("OPTIONS",_strContentBase);
xzl committed
397
}
398

399
void RtspPlayer::sendDescribe() {
400
	//发送DESCRIBE命令后处理函数:handleResDESCRIBE
401
	_onHandshake = std::bind(&RtspPlayer::handleResDESCRIBE,this, placeholders::_1);
402
	sendRtspRequest("DESCRIBE",_strUrl,{"Accept","application/sdp"});
403 404 405
}


406
void RtspPlayer::sendPause(bool bPause,uint32_t seekMS){
xzl committed
407 408
    if(!bPause){
        //修改时间轴
409
        int iTimeInc = seekMS - getProgressMilliSecond();
xiongziliang committed
410
        for(unsigned int i = 0 ;i < _aTrackInfo.size() ;i++){
411 412
			_aiFistStamp[i] = _aiNowStamp[i] + iTimeInc;
            _aiNowStamp[i] = _aiFistStamp[i];
xzl committed
413
        }
414
        _iSeekTo = seekMS;
xzl committed
415
    }
416 417

	//开启或暂停rtsp
418
	_onHandshake = std::bind(&RtspPlayer::handleResPAUSE,this, placeholders::_1,bPause);
419 420 421
	sendRtspRequest(bPause ? "PAUSE" : "PLAY",
					_strContentBase,
					{"Range",StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << seekMS / 1000.0 << "-"});
xzl committed
422 423
}
void RtspPlayer::pause(bool bPause) {
424
    sendPause(bPause, getProgressMilliSecond());
xzl committed
425 426
}

427
void RtspPlayer::handleResPAUSE(const Parser& parser, bool bPause) {
xzl committed
428 429 430 431 432 433 434 435 436 437 438 439
	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";
            }
440 441
            _iSeekTo = 1000 * atof(strStart.data());
            DebugL << "seekTo(ms):" << _iSeekTo ;
xzl committed
442 443 444 445
        }
        auto strRtpInfo =  parser["RTP-Info"];
        if (strRtpInfo.size()) {
            strRtpInfo.append(",");
446
            vector<string> vec = split(strRtpInfo, ",");
xzl committed
447
            for(auto &strTrack : vec){
448
                strTrack.append(";");
xiongziliang committed
449
                auto strControlSuffix = strTrack.substr(1 + strTrack.rfind('/'),strTrack.find(';') - strTrack.rfind('/') - 1);
450
                auto strRtpTime = FindField(strTrack.data(), "rtptime=", ";");
451
                auto idx = getTrackIndexByControlSuffix(strControlSuffix);
452 453 454 455 456
                if(idx != -1){
                    _aiFistStamp[idx] = atoll(strRtpTime.data()) * 1000 / _aTrackInfo[idx]->_samplerate;
                    _aiNowStamp[idx] = _aiFistStamp[idx];
                    DebugL << "rtptime(ms):" << strControlSuffix <<" " << strRtpTime;
                }
xzl committed
457 458
            }
        }
459
		onPlayResult_l(SockException(Err_success, "rtsp play success"));
xzl committed
460
	} else {
461
		_pRtpTimer.reset();
xzl committed
462 463 464
	}
}

465 466 467 468 469 470 471 472 473 474 475
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);
xzl committed
476 477 478
    }
}

479 480 481
void RtspPlayer::onRtpPacket(const char *data, uint64_t len) {
    int trackIdx = -1;
    uint8_t interleaved = data[1];
482
    if(interleaved %2 == 0){
483
        trackIdx = getTrackIndexByInterleaved(interleaved);
484 485 486 487 488 489
        if (trackIdx != -1) {
            handleOneRtp(trackIdx,_aTrackInfo[trackIdx],(unsigned char *)data + 4, len - 4);
        }
    }else{
        trackIdx = getTrackIndexByInterleaved(interleaved - 1);
        if (trackIdx != -1) {
490
            onRtcpPacket(trackIdx, _aTrackInfo[trackIdx], (unsigned char *) data + 4, len - 4);
491
        }
492
    }
xzl committed
493 494
}

495
void RtspPlayer::onRtcpPacket(int iTrackidx, SdpTrack::Ptr &track, unsigned char *pucData, unsigned int uiLen){
496 497 498

}

xiongziliang committed
499 500 501 502 503 504 505 506 507 508 509 510 511 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 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621

#if 0
//改代码提取自FFmpeg,参考之
// Receiver Report
    avio_w8(pb, (RTP_VERSION << 6) + 1); /* 1 report block */
    avio_w8(pb, RTCP_RR);
    avio_wb16(pb, 7); /* length in words - 1 */
    // our own SSRC: we use the server's SSRC + 1 to avoid conflicts
    avio_wb32(pb, s->ssrc + 1);
    avio_wb32(pb, s->ssrc); // server SSRC
    // some placeholders we should really fill...
    // RFC 1889/p64
    extended_max          = stats->cycles + stats->max_seq;
    expected              = extended_max - stats->base_seq;
    lost                  = expected - stats->received;
    lost                  = FFMIN(lost, 0xffffff); // clamp it since it's only 24 bits...
    expected_interval     = expected - stats->expected_prior;
    stats->expected_prior = expected;
    received_interval     = stats->received - stats->received_prior;
    stats->received_prior = stats->received;
    lost_interval         = expected_interval - received_interval;
    if (expected_interval == 0 || lost_interval <= 0)
        fraction = 0;
    else
        fraction = (lost_interval << 8) / expected_interval;

    fraction = (fraction << 24) | lost;

    avio_wb32(pb, fraction); /* 8 bits of fraction, 24 bits of total packets lost */
    avio_wb32(pb, extended_max); /* max sequence received */
    avio_wb32(pb, stats->jitter >> 4); /* jitter */

    if (s->last_rtcp_ntp_time == AV_NOPTS_VALUE) {
        avio_wb32(pb, 0); /* last SR timestamp */
        avio_wb32(pb, 0); /* delay since last SR */
    } else {
        uint32_t middle_32_bits   = s->last_rtcp_ntp_time >> 16; // this is valid, right? do we need to handle 64 bit values special?
        uint32_t delay_since_last = av_rescale(av_gettime_relative() - s->last_rtcp_reception_time,
                                               65536, AV_TIME_BASE);

        avio_wb32(pb, middle_32_bits); /* last SR timestamp */
        avio_wb32(pb, delay_since_last); /* delay since last SR */
    }

    // CNAME
    avio_w8(pb, (RTP_VERSION << 6) + 1); /* 1 report block */
    avio_w8(pb, RTCP_SDES);
    len = strlen(s->hostname);
    avio_wb16(pb, (7 + len + 3) / 4); /* length in words - 1 */
    avio_wb32(pb, s->ssrc + 1);
    avio_w8(pb, 0x01);
    avio_w8(pb, len);
    avio_write(pb, s->hostname, len);
    avio_w8(pb, 0); /* END */
    // padding
    for (len = (7 + len) % 4; len % 4; len++)
        avio_w8(pb, 0);
#endif

void RtspPlayer::sendReceiverReport(bool overTcp,int iTrackIndex){
    static const char s_cname[] = "ZLMediaKitRtsp";
    uint8_t aui8Rtcp[4 + 32 + 10 + sizeof(s_cname) + 1] = {0};
    uint8_t *pui8Rtcp_RR = aui8Rtcp + 4, *pui8Rtcp_SDES = pui8Rtcp_RR + 32;
    auto &track = _aTrackInfo[iTrackIndex];
    auto &counter = _aRtcpCnt[iTrackIndex];

    aui8Rtcp[0] = '$';
    aui8Rtcp[1] = track->_interleaved + 1;
    aui8Rtcp[2] = (sizeof(aui8Rtcp) - 4) >>  8;
    aui8Rtcp[3] = (sizeof(aui8Rtcp) - 4) & 0xFF;

    pui8Rtcp_RR[0] = 0x81;/* 1 report block */
    pui8Rtcp_RR[1] = 0xC9;//RTCP_RR
    pui8Rtcp_RR[2] = 0x00;
    pui8Rtcp_RR[3] = 0x07;/* length in words - 1 */

    uint32_t ssrc=htonl(track->_ssrc + 1);
    // our own SSRC: we use the server's SSRC + 1 to avoid conflicts
    memcpy(&pui8Rtcp_RR[4], &ssrc, 4);
    ssrc=htonl(track->_ssrc);
    // server SSRC
    memcpy(&pui8Rtcp_RR[8], &ssrc, 4);

    //FIXME: 8 bits of fraction, 24 bits of total packets lost
    pui8Rtcp_RR[12] = 0x00;
    pui8Rtcp_RR[13] = 0x00;
    pui8Rtcp_RR[14] = 0x00;
    pui8Rtcp_RR[15] = 0x00;

    //FIXME: max sequence received
    int cycleCount = getCycleCount(iTrackIndex);
    pui8Rtcp_RR[16] = cycleCount >> 8;
    pui8Rtcp_RR[17] = cycleCount & 0xFF;
    pui8Rtcp_RR[18] = counter.pktCnt >> 8;
    pui8Rtcp_RR[19] = counter.pktCnt & 0xFF;

    uint32_t  jitter = htonl(getJitterSize(iTrackIndex));
    //FIXME: jitter
    memcpy(pui8Rtcp_RR + 20, &jitter , 4);
    /* last SR timestamp */
    memcpy(pui8Rtcp_RR + 24, &counter.lastTimeStamp, 4);
    uint32_t msInc = htonl(ntohl(counter.timeStamp) - ntohl(counter.lastTimeStamp));
    /* delay since last SR */
    memcpy(pui8Rtcp_RR + 28, &msInc, 4);

    // CNAME
    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], s_cname, sizeof(s_cname));
    pui8Rtcp_SDES[10 + sizeof(s_cname)] = 0x00;

    if(overTcp){
        send(obtainBuffer((char *) aui8Rtcp, sizeof(aui8Rtcp)));
    }else if(_apRtcpSock[iTrackIndex]) {
        _apRtcpSock[iTrackIndex]->send((char *) aui8Rtcp + 4, sizeof(aui8Rtcp) - 4);
    }
622
}
xzl committed
623

xiongziliang committed
624

xiongziliang committed
625
void RtspPlayer::onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx){
xzl committed
626
	//统计丢包率
627 628 629
	if (_aui16FirstSeq[trackidx] == 0 || rtppt->sequence < _aui16FirstSeq[trackidx]) {
		_aui16FirstSeq[trackidx] = rtppt->sequence;
		_aui64RtpRecv[trackidx] = 0;
xzl committed
630
	}
631 632
	_aui64RtpRecv[trackidx] ++;
	_aui16NowSeq[trackidx] = rtppt->sequence;
633
	_aiNowStamp[trackidx] = rtppt->timeStamp;
634 635 636
	if( _aiFistStamp[trackidx] == 0){
		_aiFistStamp[trackidx] = _aiNowStamp[trackidx];
	}
637 638

    rtppt->timeStamp -= _aiFistStamp[trackidx];
639
	onRecvRTP_l(rtppt,_aTrackInfo[trackidx]);
xzl committed
640
}
641
float RtspPlayer::getPacketLossRate(TrackType type) const{
xiongziliang committed
642
	int iTrackIdx = getTrackIndexByTrackType(type);
xzl committed
643 644 645
	if(iTrackIdx == -1){
		uint64_t totalRecv = 0;
		uint64_t totalSend = 0;
xiongziliang committed
646
		for (unsigned int i = 0; i < _aTrackInfo.size(); i++) {
647 648
			totalRecv += _aui64RtpRecv[i];
			totalSend += (_aui16NowSeq[i] - _aui16FirstSeq[i] + 1);
xzl committed
649 650 651 652 653 654 655 656
		}
		if(totalSend == 0){
			return 0;
		}
		return 1.0 - (double)totalRecv / totalSend;
	}


657
	if(_aui16NowSeq[iTrackIdx] - _aui16FirstSeq[iTrackIdx] + 1 == 0){
xzl committed
658 659
		return 0;
	}
660
	return 1.0 - (double)_aui64RtpRecv[iTrackIdx] / (_aui16NowSeq[iTrackIdx] - _aui16FirstSeq[iTrackIdx] + 1);
xzl committed
661 662
}

663 664
uint32_t RtspPlayer::getProgressMilliSecond() const{
	uint32_t iTime[2] = {0,0};
xiongziliang committed
665
    for(unsigned int i = 0 ;i < _aTrackInfo.size() ;i++){
666
		iTime[i] = _aiNowStamp[i] - _aiFistStamp[i];
xzl committed
667
    }
668
    return _iSeekTo + MAX(iTime[0],iTime[1]);
xzl committed
669
}
670 671
void RtspPlayer::seekToMilliSecond(uint32_t ms) {
    sendPause(false,ms);
xzl committed
672
}
673

674
void RtspPlayer::sendRtspRequest(const string &cmd, const string &url, const std::initializer_list<string> &header) {
xiongziliang committed
675 676 677 678 679 680 681 682 683 684
	string key;
	StrCaseMap header_map;
	int i = 0;
	for(auto &val : header){
		if(++i % 2 == 0){
			header_map.emplace(key,val);
		}else{
			key = val;
		}
	}
685
	sendRtspRequest(cmd,url,header_map);
xiongziliang committed
686
}
687
void RtspPlayer::sendRtspRequest(const string &cmd, const string &url,const StrCaseMap &header_const) {
688
	auto header = header_const;
689
	header.emplace("CSeq",StrPrinter << _uiCseq++);
xiongziliang committed
690 691
	header.emplace("User-Agent",SERVER_NAME "(build in " __DATE__ " " __TIME__ ")");

692 693
	if(!_strSession.empty()){
		header.emplace("Session",_strSession);
694 695
	}

xiongziliang committed
696
	if(!_rtspRealm.empty() && !(*this)[kRtspUser].empty()){
xiongziliang committed
697
		if(!_rtspMd5Nonce.empty()){
698 699 700 701 702 703 704 705 706
			//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) );
			 */
xiongziliang committed
707 708 709
			string encrypted_pwd = (*this)[kRtspPwd];
			if(!(*this)[kRtspPwdIsMD5].as<bool>()){
				encrypted_pwd = MD5((*this)[kRtspUser]+ ":" + _rtspRealm + ":" + encrypted_pwd).hexdigest();
710
			}
xiongziliang committed
711
			auto response = MD5( encrypted_pwd + ":" + _rtspMd5Nonce  + ":" + MD5(cmd + ":" + url).hexdigest()).hexdigest();
712 713
			_StrPrinter printer;
			printer << "Digest ";
xiongziliang committed
714
			printer << "username=\"" << (*this)[kRtspUser] << "\", ";
xiongziliang committed
715 716
			printer << "realm=\"" << _rtspRealm << "\", ";
			printer << "nonce=\"" << _rtspMd5Nonce << "\", ";
717 718 719
			printer << "uri=\"" << url << "\", ";
			printer << "response=\"" << response << "\"";
			header.emplace("Authorization",printer);
xiongziliang committed
720
		}else if(!(*this)[kRtspPwdIsMD5].as<bool>()){
721
			//base64认证
xiongziliang committed
722
			string authStr = StrPrinter << (*this)[kRtspUser] << ":" << (*this)[kRtspPwd];
723 724 725 726 727 728 729 730 731 732 733
			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";
	}
734
	send(printer << "\r\n");
735 736
}

xiongziliang committed
737
void RtspPlayer::onRecvRTP_l(const RtpPacket::Ptr &pkt, const SdpTrack::Ptr &track) {
738
	_rtpTicker.resetTime();
xiongziliang committed
739 740 741 742 743 744 745 746 747 748 749 750 751
    onRecvRTP(pkt,track);

    int iTrackIndex = getTrackIndexByInterleaved(pkt->interleaved);
    if(iTrackIndex == -1){
        return;
    }
    RtcpCounter &counter = _aRtcpCnt[iTrackIndex];
    counter.pktCnt = pkt->sequence;
    auto &ticker = _aRtcpTicker[iTrackIndex];
    if (ticker.elapsedTime() > 5 * 1000) {
        //send rtcp every 5 second
        counter.lastTimeStamp = counter.timeStamp;
        //直接保存网络字节序
xiongziliang committed
752
        memcpy(&counter.timeStamp, pkt->data() + 8 , 4);
xiongziliang committed
753 754 755 756 757 758 759
        if(counter.lastTimeStamp != 0){
            sendReceiverReport(_eType == Rtsp::RTP_TCP,iTrackIndex);
            ticker.resetTime();
        }
    }


760 761 762
}
void RtspPlayer::onPlayResult_l(const SockException &ex) {
	WarnL << ex.getErrCode() << " " << ex.what();
763

764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
    if(!ex){
        //播放成功,恢复rtp接收超时定时器
        _rtpTicker.resetTime();
        weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this());
        int timeoutMS = (*this)[kMediaTimeoutMS].as<int>();
        _pRtpTimer.reset( new Timer(timeoutMS / 2000.0, [weakSelf,timeoutMS]() {
            auto strongSelf=weakSelf.lock();
            if(!strongSelf) {
                return false;
            }
            if(strongSelf->_rtpTicker.elapsedTime()> timeoutMS) {
                //recv rtp timeout!
                strongSelf->onPlayResult_l(SockException(Err_timeout,"recv rtp timeout"));
                return false;
            }
            return true;
        },getPoller()));
    }

    if (_pPlayTimer) {
        //开始播放阶段
        _pPlayTimer.reset();
        onPlayResult(ex);
    }else {
        //播放中途阶段
        if (ex) {
            //播放成功后异常断开回调
            onShutdown(ex);
        }else{
            //恢复播放
            onResume();
        }
    }

    if(ex){
        teardown();
    }
801 802
}

xiongziliang committed
803
int RtspPlayer::getTrackIndexByControlSuffix(const string &controlSuffix) const{
xiongziliang committed
804
	for (unsigned int i = 0; i < _aTrackInfo.size(); i++) {
805 806
		auto pos = _aTrackInfo[i]->_control_surffix.find(controlSuffix);
		if (pos == 0) {
807 808 809 810 811
			return i;
		}
	}
	return -1;
}
xiongziliang committed
812
int RtspPlayer::getTrackIndexByInterleaved(int interleaved) const{
xiongziliang committed
813
	for (unsigned int i = 0; i < _aTrackInfo.size(); i++) {
814
		if (_aTrackInfo[i]->_interleaved == interleaved) {
xiongziliang committed
815 816 817 818 819 820 821
			return i;
		}
	}
	return -1;
}

int RtspPlayer::getTrackIndexByTrackType(TrackType trackType) const {
xiongziliang committed
822
	for (unsigned int i = 0; i < _aTrackInfo.size(); i++) {
823
		if (_aTrackInfo[i]->_type == trackType) {
824 825 826 827 828 829
			return i;
		}
	}
	return -1;
}

xiongziliang committed
830
} /* namespace mediakit */
xzl committed
831 832