解决播放成功与中途断开事件触发紊乱的问题:#143

This commit is contained in:
xiongziliang 2019-11-19 15:52:02 +08:00
parent 85cd4a7d02
commit e6d511cc9e
5 changed files with 140 additions and 127 deletions

@ -1 +1 @@
Subproject commit 40edf6243d9d99676062062efdec203b24a178aa Subproject commit 678678b2ee7118d21d33a90a303698e0da02790c

View File

@ -34,44 +34,35 @@ using namespace mediakit::Client;
namespace mediakit { namespace mediakit {
unordered_map<string, RtmpPlayer::rtmpCMDHandle> RtmpPlayer::g_mapCmd;
RtmpPlayer::RtmpPlayer(const EventPoller::Ptr &poller) : TcpClient(poller) { RtmpPlayer::RtmpPlayer(const EventPoller::Ptr &poller) : TcpClient(poller) {
static onceToken token([]() {
g_mapCmd.emplace("_error",&RtmpPlayer::onCmd_result);
g_mapCmd.emplace("_result",&RtmpPlayer::onCmd_result);
g_mapCmd.emplace("onStatus",&RtmpPlayer::onCmd_onStatus);
g_mapCmd.emplace("onMetaData",&RtmpPlayer::onCmd_onMetaData);
}, []() {});
} }
RtmpPlayer::~RtmpPlayer() { RtmpPlayer::~RtmpPlayer() {
DebugL << endl; DebugL << endl;
} }
void RtmpPlayer::teardown() { void RtmpPlayer::teardown() {
if (alive()) { if (alive()) {
shutdown(SockException(Err_shutdown,"teardown"));
}
_strApp.clear(); _strApp.clear();
_strStream.clear(); _strStream.clear();
_strTcUrl.clear(); _strTcUrl.clear();
{
lock_guard<recursive_mutex> lck(_mtxOnResultCB);
_mapOnResultCB.clear();
}
{
lock_guard<recursive_mutex> lck(_mtxOnStatusCB);
_dqOnStatusCB.clear();
}
_pBeatTimer.reset(); _pBeatTimer.reset();
_pPlayTimer.reset(); _pPlayTimer.reset();
_pMediaTimer.reset(); _pMediaTimer.reset();
_iSeekTo = 0; _iSeekTo = 0;
RtmpProtocol::reset();
CLEAR_ARR(_aiFistStamp); CLEAR_ARR(_aiFistStamp);
CLEAR_ARR(_aiNowStamp); CLEAR_ARR(_aiNowStamp);
reset();
shutdown(SockException(Err_shutdown,"teardown")); lock_guard<recursive_mutex> lck(_mtxOnResultCB);
} _mapOnResultCB.clear();
lock_guard<recursive_mutex> lck2(_mtxOnStatusCB);
_dqOnStatusCB.clear();
} }
void RtmpPlayer::play(const string &strUrl) { void RtmpPlayer::play(const string &strUrl) {
teardown(); teardown();
string strHost = FindField(strUrl.data(), "://", "/"); string strHost = FindField(strUrl.data(), "://", "/");
@ -80,7 +71,7 @@ void RtmpPlayer::play(const string &strUrl) {
_strTcUrl = string("rtmp://") + strHost + "/" + _strApp; _strTcUrl = string("rtmp://") + strHost + "/" + _strApp;
if (!_strApp.size() || !_strStream.size()) { if (!_strApp.size() || !_strStream.size()) {
onPlayResult_l(SockException(Err_other,"rtmp url非法")); onPlayResult_l(SockException(Err_other,"rtmp url非法"),false);
return; return;
} }
DebugL << strHost << " " << _strApp << " " << _strStream; DebugL << strHost << " " << _strApp << " " << _strStream;
@ -104,7 +95,7 @@ void RtmpPlayer::play(const string &strUrl) {
if(!strongSelf) { if(!strongSelf) {
return false; return false;
} }
strongSelf->onPlayResult_l(SockException(Err_timeout,"play rtmp timeout")); strongSelf->onPlayResult_l(SockException(Err_timeout,"play rtmp timeout"),false);
return false; return false;
},getPoller())); },getPoller()));
@ -112,45 +103,44 @@ void RtmpPlayer::play(const string &strUrl) {
startConnect(strHost, iPort , playTimeOutSec); startConnect(strHost, iPort , playTimeOutSec);
} }
void RtmpPlayer::onErr(const SockException &ex){ void RtmpPlayer::onErr(const SockException &ex){
onPlayResult_l(ex); //定时器_pPlayTimer为空后表明握手结束了
onPlayResult_l(ex, !_pPlayTimer);
} }
void RtmpPlayer::onPlayResult_l(const SockException &ex) { void RtmpPlayer::onPlayResult_l(const SockException &ex , bool handshakeCompleted) {
WarnL << ex.getErrCode() << " " << ex.what(); WarnL << ex.getErrCode() << " " << ex.what();
if(!ex){ if(!ex){
//恢复rtmp接收超时定时器 //播放成功,恢复rtmp接收超时定时器
_mediaTicker.resetTime(); _mediaTicker.resetTime();
weak_ptr<RtmpPlayer> weakSelf = dynamic_pointer_cast<RtmpPlayer>(shared_from_this()); weak_ptr<RtmpPlayer> weakSelf = dynamic_pointer_cast<RtmpPlayer>(shared_from_this());
int timeoutMS = (*this)[kMediaTimeoutMS].as<int>(); int timeoutMS = (*this)[kMediaTimeoutMS].as<int>();
//创建rtmp数据接收超时检测定时器
_pMediaTimer.reset( new Timer(timeoutMS / 2000.0, [weakSelf,timeoutMS]() { _pMediaTimer.reset( new Timer(timeoutMS / 2000.0, [weakSelf,timeoutMS]() {
auto strongSelf=weakSelf.lock(); auto strongSelf=weakSelf.lock();
if(!strongSelf) { if(!strongSelf) {
return false; return false;
} }
if(strongSelf->_mediaTicker.elapsedTime()> timeoutMS) { if(strongSelf->_mediaTicker.elapsedTime()> timeoutMS) {
//recv media timeout! //接收rtmp媒体数据超时
strongSelf->onPlayResult_l(SockException(Err_timeout,"recv rtmp timeout")); strongSelf->onPlayResult_l(SockException(Err_timeout,"receive rtmp timeout"),true);
return false; return false;
} }
return true; return true;
},getPoller())); },getPoller()));
} }
if (_pPlayTimer) { if (!handshakeCompleted) {
//开始播放阶段 //开始播放阶段
_pPlayTimer.reset(); _pPlayTimer.reset();
onPlayResult(ex); onPlayResult(ex);
}else { } else if (ex) {
//播放中途阶段
if (ex) {
//播放成功后异常断开回调 //播放成功后异常断开回调
onShutdown(ex); onShutdown(ex);
} else { } else {
//恢复播放 //恢复播放
onResume(); onResume();
} }
}
if(ex){ if(ex){
teardown(); teardown();
@ -158,7 +148,7 @@ void RtmpPlayer::onPlayResult_l(const SockException &ex) {
} }
void RtmpPlayer::onConnect(const SockException &err){ void RtmpPlayer::onConnect(const SockException &err){
if(err.getErrCode() != Err_success) { if(err.getErrCode() != Err_success) {
onPlayResult_l(err); onPlayResult_l(err, false);
return; return;
} }
weak_ptr<RtmpPlayer> weakSelf= dynamic_pointer_cast<RtmpPlayer>(shared_from_this()); weak_ptr<RtmpPlayer> weakSelf= dynamic_pointer_cast<RtmpPlayer>(shared_from_this());
@ -175,7 +165,8 @@ void RtmpPlayer::onRecv(const Buffer::Ptr &pBuf){
onParseRtmp(pBuf->data(), pBuf->size()); onParseRtmp(pBuf->data(), pBuf->size());
} catch (exception &e) { } catch (exception &e) {
SockException ex(Err_other, e.what()); SockException ex(Err_other, e.what());
onPlayResult_l(ex); //定时器_pPlayTimer为空后表明握手结束了
onPlayResult_l(ex, !_pPlayTimer);
} }
} }
@ -253,7 +244,7 @@ inline void RtmpPlayer::send_pause(bool bPause) {
}else{ }else{
_bPaused = bPause; _bPaused = bPause;
if(!bPause){ if(!bPause){
onPlayResult_l(SockException(Err_success, "rtmp resum success")); onPlayResult_l(SockException(Err_success, "resum rtmp success"), true);
}else{ }else{
//暂停播放 //暂停播放
_pMediaTimer.reset(); _pMediaTimer.reset();
@ -327,7 +318,7 @@ void RtmpPlayer::onCmd_onMetaData(AMFDecoder &dec) {
void RtmpPlayer::onStreamDry(uint32_t ui32StreamId) { void RtmpPlayer::onStreamDry(uint32_t ui32StreamId) {
//TraceL << ui32StreamId; //TraceL << ui32StreamId;
onPlayResult_l(SockException(Err_other,"rtmp stream dry")); onPlayResult_l(SockException(Err_other,"rtmp stream dry"), true);
} }
void RtmpPlayer::onMediaData_l(const RtmpPacket::Ptr &packet) { void RtmpPlayer::onMediaData_l(const RtmpPacket::Ptr &packet) {
@ -343,7 +334,7 @@ void RtmpPlayer::onMediaData_l(const RtmpPacket::Ptr &packet) {
onMediaData(packet); onMediaData(packet);
}else{ }else{
//先触发onPlayResult事件这个时候解码器才能初始化完毕 //先触发onPlayResult事件这个时候解码器才能初始化完毕
onPlayResult_l(SockException(Err_success,"play rtmp success")); onPlayResult_l(SockException(Err_success,"play rtmp success"), false);
//触发onPlayResult事件后再把帧数据输入到解码器 //触发onPlayResult事件后再把帧数据输入到解码器
onMediaData(packet); onMediaData(packet);
} }
@ -351,6 +342,15 @@ void RtmpPlayer::onMediaData_l(const RtmpPacket::Ptr &packet) {
void RtmpPlayer::onRtmpChunk(RtmpPacket &chunkData) { void RtmpPlayer::onRtmpChunk(RtmpPacket &chunkData) {
typedef void (RtmpPlayer::*rtmp_func_ptr)(AMFDecoder &dec);
static unordered_map<string, rtmp_func_ptr> s_func_map;
static onceToken token([]() {
s_func_map.emplace("_error",&RtmpPlayer::onCmd_result);
s_func_map.emplace("_result",&RtmpPlayer::onCmd_result);
s_func_map.emplace("onStatus",&RtmpPlayer::onCmd_onStatus);
s_func_map.emplace("onMetaData",&RtmpPlayer::onCmd_onMetaData);
}, []() {});
switch (chunkData.typeId) { switch (chunkData.typeId) {
case MSG_CMD: case MSG_CMD:
case MSG_CMD3: case MSG_CMD3:
@ -358,8 +358,8 @@ void RtmpPlayer::onRtmpChunk(RtmpPacket &chunkData) {
case MSG_DATA3: { case MSG_DATA3: {
AMFDecoder dec(chunkData.strBuf, 0); AMFDecoder dec(chunkData.strBuf, 0);
std::string type = dec.load<std::string>(); std::string type = dec.load<std::string>();
auto it = g_mapCmd.find(type); auto it = s_func_map.find(type);
if(it != g_mapCmd.end()){ if(it != s_func_map.end()){
auto fun = it->second; auto fun = it->second;
(this->*fun)(dec); (this->*fun)(dec);
}else{ }else{

View File

@ -61,7 +61,7 @@ protected:
void seekToMilliSecond(uint32_t ms); void seekToMilliSecond(uint32_t ms);
protected: protected:
void onMediaData_l(const RtmpPacket::Ptr &chunkData); void onMediaData_l(const RtmpPacket::Ptr &chunkData);
void onPlayResult_l(const SockException &ex); void onPlayResult_l(const SockException &ex, bool handshakeCompleted);
//form Tcpclient //form Tcpclient
void onRecv(const Buffer::Ptr &pBuf) override; void onRecv(const Buffer::Ptr &pBuf) override;
@ -104,9 +104,6 @@ private:
deque<function<void(AMFValue &dec)> > _dqOnStatusCB; deque<function<void(AMFValue &dec)> > _dqOnStatusCB;
recursive_mutex _mtxOnStatusCB; recursive_mutex _mtxOnStatusCB;
typedef void (RtmpPlayer::*rtmpCMDHandle)(AMFDecoder &dec);
static unordered_map<string, rtmpCMDHandle> g_mapCmd;
//超时功能实现 //超时功能实现
Ticker _mediaTicker; Ticker _mediaTicker;
std::shared_ptr<Timer> _pMediaTimer; std::shared_ptr<Timer> _pMediaTimer;

View File

@ -42,6 +42,12 @@ using namespace mediakit::Client;
namespace mediakit { namespace mediakit {
enum PlayType {
type_play = 0,
type_pause,
type_seek
};
RtspPlayer::RtspPlayer(const EventPoller::Ptr &poller) : TcpClient(poller){ RtspPlayer::RtspPlayer(const EventPoller::Ptr &poller) : TcpClient(poller){
RtpReceiver::setPoolSize(64); RtpReceiver::setPoolSize(64);
} }
@ -56,7 +62,6 @@ void RtspPlayer::teardown(){
_rtspMd5Nonce.clear(); _rtspMd5Nonce.clear();
_rtspRealm.clear(); _rtspRealm.clear();
_aTrackInfo.clear(); _aTrackInfo.clear();
_strSession.clear(); _strSession.clear();
_strContentBase.clear(); _strContentBase.clear();
@ -135,7 +140,7 @@ void RtspPlayer::play(bool isSSL,const string &strUrl, const string &strUser, co
} }
if(ip.empty()){ if(ip.empty()){
onPlayResult_l(SockException(Err_other,StrPrinter << "illegal rtsp url:" << strUrl)); onPlayResult_l(SockException(Err_other,StrPrinter << "illegal rtsp url:" << strUrl),false);
return; return;
} }
@ -148,7 +153,7 @@ void RtspPlayer::play(bool isSSL,const string &strUrl, const string &strUser, co
if(!strongSelf) { if(!strongSelf) {
return false; return false;
} }
strongSelf->onPlayResult_l(SockException(Err_timeout,"play rtsp timeout")); strongSelf->onPlayResult_l(SockException(Err_timeout,"play rtsp timeout"),false);
return false; return false;
},getPoller())); },getPoller()));
@ -159,7 +164,7 @@ void RtspPlayer::play(bool isSSL,const string &strUrl, const string &strUser, co
} }
void RtspPlayer::onConnect(const SockException &err){ void RtspPlayer::onConnect(const SockException &err){
if(err.getErrCode() != Err_success) { if(err.getErrCode() != Err_success) {
onPlayResult_l(err); onPlayResult_l(err,false);
return; return;
} }
@ -170,7 +175,8 @@ void RtspPlayer::onRecv(const Buffer::Ptr& pBuf) {
input(pBuf->data(),pBuf->size()); input(pBuf->data(),pBuf->size());
} }
void RtspPlayer::onErr(const SockException &ex) { void RtspPlayer::onErr(const SockException &ex) {
onPlayResult_l(ex); //定时器_pPlayTimer为空后表明握手结束了
onPlayResult_l(ex,!_pPlayTimer);
} }
// from live555 // from live555
bool RtspPlayer::handleAuthenticationFailure(const string &paramsStr) { bool RtspPlayer::handleAuthenticationFailure(const string &paramsStr) {
@ -403,8 +409,7 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int uiTrackIndex)
WarnL << "收到其他地址的rtcp数据:" << inet_ntoa(((struct sockaddr_in *) addr)->sin_addr); WarnL << "收到其他地址的rtcp数据:" << inet_ntoa(((struct sockaddr_in *) addr)->sin_addr);
return; return;
} }
strongSelf->onRtcpPacket(uiTrackIndex, strongSelf->_aTrackInfo[uiTrackIndex], strongSelf->onRtcpPacket(uiTrackIndex, strongSelf->_aTrackInfo[uiTrackIndex], (unsigned char *) buf->data(), buf->size());
(unsigned char *) buf->data(), buf->size());
}); });
} }
} }
@ -416,14 +421,7 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int uiTrackIndex)
} }
//所有setup命令发送完毕 //所有setup命令发送完毕
//发送play命令 //发送play命令
sendPause(false, 0,false); sendPause(type_play, 0);
}
void RtspPlayer::sendOptions() {
_onHandshake = [](const Parser& parser){
// DebugL << "options response";
};
sendRtspRequest("OPTIONS",_strContentBase);
} }
void RtspPlayer::sendDescribe() { void RtspPlayer::sendDescribe() {
@ -432,28 +430,52 @@ void RtspPlayer::sendDescribe() {
sendRtspRequest("DESCRIBE",_strUrl,{"Accept","application/sdp"}); sendRtspRequest("DESCRIBE",_strUrl,{"Accept","application/sdp"});
} }
void RtspPlayer::sendPause(int type , uint32_t seekMS){
void RtspPlayer::sendPause(bool bPause,uint32_t seekMS,bool range){ _onHandshake = std::bind(&RtspPlayer::handleResPAUSE,this, placeholders::_1,type);
//开启或暂停rtsp //开启或暂停rtsp
_onHandshake = std::bind(&RtspPlayer::handleResPAUSE,this, placeholders::_1,bPause); switch (type){
if(!bPause && range){ case type_pause:
sendRtspRequest(bPause ? "PAUSE" : "PLAY", _strContentBase, sendRtspRequest("PAUSE", _strContentBase);
{"Range",StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << seekMS / 1000.0 << "-"}); break;
} else{ case type_play:
sendRtspRequest(bPause ? "PAUSE" : "PLAY", _strContentBase); sendRtspRequest("PLAY", _strContentBase);
break;
case type_seek:
sendRtspRequest("PLAY", _strContentBase, {"Range",StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << seekMS / 1000.0 << "-"});
break;
default:
WarnL << "unknown type : " << type;
_onHandshake = nullptr;
break;
} }
} }
void RtspPlayer::pause(bool bPause) { void RtspPlayer::pause(bool bPause) {
sendPause(bPause, getProgressMilliSecond(),false); sendPause(bPause ? type_pause : type_seek, getProgressMilliSecond());
} }
void RtspPlayer::handleResPAUSE(const Parser& parser, bool bPause) { void RtspPlayer::handleResPAUSE(const Parser& parser,int type) {
if (parser.Url() != "200") { if (parser.Url() != "200") {
WarnL <<(bPause ? "Pause" : "Play") << " failed:" << parser.Url() << " " << parser.Tail() << endl; switch (type) {
case type_pause:
WarnL << "Pause failed:" << parser.Url() << " " << parser.Tail() << endl;
break;
case type_play:
WarnL << "Play failed:" << parser.Url() << " " << parser.Tail() << endl;
break;
case type_seek:
WarnL << "Seek failed:" << parser.Url() << " " << parser.Tail() << endl;
break;
}
return; return;
} }
if (!bPause) {
if (type == type_pause) {
//暂停成功!
_pRtpTimer.reset();
return;
}
//play或seek成功
uint32_t iSeekTo = 0; uint32_t iSeekTo = 0;
//修正时间轴 //修正时间轴
auto strRange = parser["Range"]; auto strRange = parser["Range"];
@ -468,10 +490,7 @@ void RtspPlayer::handleResPAUSE(const Parser& parser, bool bPause) {
//设置相对时间戳 //设置相对时间戳
_stamp[0].setRelativeStamp(iSeekTo); _stamp[0].setRelativeStamp(iSeekTo);
_stamp[1].setRelativeStamp(iSeekTo); _stamp[1].setRelativeStamp(iSeekTo);
onPlayResult_l(SockException(Err_success, "rtsp play success")); onPlayResult_l(SockException(Err_success, type == type_seek ? "resum rtsp success" : "rtsp play success"), type == type_seek);
} else {
_pRtpTimer.reset();
}
} }
void RtspPlayer::onWholeRtspPacket(Parser &parser) { void RtspPlayer::onWholeRtspPacket(Parser &parser) {
@ -483,8 +502,8 @@ void RtspPlayer::onWholeRtspPacket(Parser &parser) {
} }
parser.Clear(); parser.Clear();
} catch (std::exception &err) { } catch (std::exception &err) {
SockException ex(Err_other, err.what()); //定时器_pPlayTimer为空后表明握手结束了
onPlayResult_l(ex); onPlayResult_l(SockException(Err_other, err.what()),!_pPlayTimer);
} }
} }
@ -674,7 +693,7 @@ uint32_t RtspPlayer::getProgressMilliSecond() const{
return MAX(_stamp[0].getRelativeStamp(),_stamp[1].getRelativeStamp()); return MAX(_stamp[0].getRelativeStamp(),_stamp[1].getRelativeStamp());
} }
void RtspPlayer::seekToMilliSecond(uint32_t ms) { void RtspPlayer::seekToMilliSecond(uint32_t ms) {
sendPause(false,ms, true); sendPause(type_seek,ms);
} }
void RtspPlayer::sendRtspRequest(const string &cmd, const string &url, const std::initializer_list<string> &header) { void RtspPlayer::sendRtspRequest(const string &cmd, const string &url, const std::initializer_list<string> &header) {
@ -764,7 +783,7 @@ void RtspPlayer::onRecvRTP_l(const RtpPacket::Ptr &pkt, const SdpTrack::Ptr &tra
} }
void RtspPlayer::onPlayResult_l(const SockException &ex) { void RtspPlayer::onPlayResult_l(const SockException &ex , bool handshakeCompleted) {
WarnL << ex.getErrCode() << " " << ex.what(); WarnL << ex.getErrCode() << " " << ex.what();
if(!ex){ if(!ex){
@ -772,34 +791,32 @@ void RtspPlayer::onPlayResult_l(const SockException &ex) {
_rtpTicker.resetTime(); _rtpTicker.resetTime();
weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this()); weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this());
int timeoutMS = (*this)[kMediaTimeoutMS].as<int>(); int timeoutMS = (*this)[kMediaTimeoutMS].as<int>();
//创建rtp数据接收超时检测定时器
_pRtpTimer.reset( new Timer(timeoutMS / 2000.0, [weakSelf,timeoutMS]() { _pRtpTimer.reset( new Timer(timeoutMS / 2000.0, [weakSelf,timeoutMS]() {
auto strongSelf=weakSelf.lock(); auto strongSelf=weakSelf.lock();
if(!strongSelf) { if(!strongSelf) {
return false; return false;
} }
if(strongSelf->_rtpTicker.elapsedTime()> timeoutMS) { if(strongSelf->_rtpTicker.elapsedTime()> timeoutMS) {
//recv rtp timeout! //接收rtp媒体数据包超时
strongSelf->onPlayResult_l(SockException(Err_timeout,"recv rtp timeout")); strongSelf->onPlayResult_l(SockException(Err_timeout,"receive rtp timeout"), true);
return false; return false;
} }
return true; return true;
},getPoller())); },getPoller()));
} }
if (_pPlayTimer) { if (!handshakeCompleted) {
//开始播放阶段 //开始播放阶段
_pPlayTimer.reset(); _pPlayTimer.reset();
onPlayResult(ex); onPlayResult(ex);
}else { } else if (ex) {
//播放中途阶段
if (ex) {
//播放成功后异常断开回调 //播放成功后异常断开回调
onShutdown(ex); onShutdown(ex);
} else { } else {
//恢复播放 //恢复播放
onResume(); onResume();
} }
}
if(ex){ if(ex){
teardown(); teardown();

View File

@ -101,7 +101,7 @@ protected:
void onErr(const SockException &ex) override; void onErr(const SockException &ex) override;
private: private:
void onRecvRTP_l(const RtpPacket::Ptr &pRtppt, const SdpTrack::Ptr &track); void onRecvRTP_l(const RtpPacket::Ptr &pRtppt, const SdpTrack::Ptr &track);
void onPlayResult_l(const SockException &ex); void onPlayResult_l(const SockException &ex , bool handshakeCompleted);
int getTrackIndexByControlSuffix(const string &controlSuffix) const; int getTrackIndexByControlSuffix(const string &controlSuffix) const;
int getTrackIndexByInterleaved(int interleaved) const; int getTrackIndexByInterleaved(int interleaved) const;
@ -111,12 +111,11 @@ private:
void handleResSETUP(const Parser &parser, unsigned int uiTrackIndex); void handleResSETUP(const Parser &parser, unsigned int uiTrackIndex);
void handleResDESCRIBE(const Parser &parser); void handleResDESCRIBE(const Parser &parser);
bool handleAuthenticationFailure(const string &wwwAuthenticateParamsStr); bool handleAuthenticationFailure(const string &wwwAuthenticateParamsStr);
void handleResPAUSE(const Parser &parser, bool bPause); void handleResPAUSE(const Parser &parser, int type);
//发送SETUP命令 //发送SETUP命令
void sendSetup(unsigned int uiTrackIndex); void sendSetup(unsigned int uiTrackIndex);
void sendPause(bool bPause,uint32_t ms, bool range); void sendPause(int type , uint32_t ms);
void sendOptions();
void sendDescribe(); void sendDescribe();
void sendRtspRequest(const string &cmd, const string &url ,const StrCaseMap &header = StrCaseMap()); void sendRtspRequest(const string &cmd, const string &url ,const StrCaseMap &header = StrCaseMap());