From 8d1801339c38429481f615361900cfcf812fb84a Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Mon, 25 May 2020 18:22:21 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96rtsp=E9=89=B4=E6=9D=83?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- conf/config.ini | 3 +- src/Rtsp/RtspSession.cpp | 226 ++++++++++++++++++++------------------- src/Rtsp/RtspSession.h | 8 +- 3 files changed, 123 insertions(+), 114 deletions(-) diff --git a/conf/config.ini b/conf/config.ini index 78abb92d..e4ba3cc1 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -85,8 +85,9 @@ on_publish=https://127.0.0.1/index/hook/on_publish on_record_mp4=https://127.0.0.1/index/hook/on_record_mp4 #rtsp播放鉴权事件,此事件中比对rtsp的用户名密码 on_rtsp_auth=https://127.0.0.1/index/hook/on_rtsp_auth -#rtsp播放是否开启鉴权事件,置空则关闭rtsp鉴权。rtsp播放鉴权还支持url方式鉴权 +#rtsp播放是否开启专属鉴权事件,置空则关闭rtsp鉴权。rtsp播放鉴权还支持url方式鉴权 #建议开发者统一采用url参数方式鉴权,rtsp用户名密码鉴权一般在设备上用的比较多 +#开启rtsp专属鉴权后,将不再触发on_play鉴权事件 on_rtsp_realm=https://127.0.0.1/index/hook/on_rtsp_realm #远程telnet调试鉴权事件 on_shell_login=https://127.0.0.1/index/hook/on_shell_login diff --git a/src/Rtsp/RtspSession.cpp b/src/Rtsp/RtspSession.cpp index c8f7e04e..57c1647b 100644 --- a/src/Rtsp/RtspSession.cpp +++ b/src/Rtsp/RtspSession.cpp @@ -318,38 +318,80 @@ void RtspSession::handleReq_RECORD(const Parser &parser){ } } -void RtspSession::handleReq_Describe(const Parser &parser) { +void RtspSession::emitOnPlay(){ weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); + //url鉴权回调 + auto onRes = [weakSelf](const string &err) { + auto strongSelf = weakSelf.lock(); + if (!strongSelf) { + return; + } + if (!err.empty()) { + //播放url鉴权失败 + strongSelf->sendRtspResponse("401 Unauthorized", {"Content-Type", "text/plain"}, err); + strongSelf->shutdown(SockException(Err_shutdown, StrPrinter << "401 Unauthorized:" << err)); + return; + } + strongSelf->onAuthSuccess(); + }; + + Broadcast::AuthInvoker invoker = [weakSelf, onRes](const string &err) { + auto strongSelf = weakSelf.lock(); + if (!strongSelf) { + return; + } + strongSelf->async([onRes, err, weakSelf]() { + onRes(err); + }); + }; + + //广播通用播放url鉴权事件 + auto flag = _emit_on_play ? false : NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed, _mediaInfo, invoker, static_cast(*this)); + if (!flag) { + //该事件无人监听,默认不鉴权 + onRes(""); + } + //已经鉴权过了 + _emit_on_play = true; +} + +void RtspSession::handleReq_Describe(const Parser &parser) { //该请求中的认证信息 auto authorization = parser["Authorization"]; - onGetRealm invoker = [weakSelf,authorization](const string &realm){ + weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); + //rtsp专属鉴权是否开启事件回调 + onGetRealm invoker = [weakSelf, authorization](const string &realm) { auto strongSelf = weakSelf.lock(); - if(!strongSelf){ + if (!strongSelf) { //本对象已经销毁 return; } //切换到自己的线程然后执行 - strongSelf->async([weakSelf,realm,authorization](){ + strongSelf->async([weakSelf, realm, authorization]() { auto strongSelf = weakSelf.lock(); - if(!strongSelf){ + if (!strongSelf) { //本对象已经销毁 return; } - if(realm.empty()){ - //无需认证,回复sdp - strongSelf->onAuthSuccess(); + if (realm.empty()) { + //无需rtsp专属认证, 那么继续url通用鉴权认证(on_play) + strongSelf->emitOnPlay(); return; } - //该流需要认证 - strongSelf->onAuthUser(realm,authorization); + //该流需要rtsp专属认证,开启rtsp专属认证后,将不再触发url通用鉴权认证(on_play) + strongSelf->_rtsp_realm = realm; + strongSelf->onAuthUser(realm, authorization); }); - }; - //广播是否需要认证事件 - if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnGetRtspRealm,_mediaInfo,invoker,static_cast(*this))){ - //无人监听此事件,说明无需认证 - invoker(""); + if(_rtsp_realm.empty()){ + //广播是否需要rtsp专属认证事件 + if (!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnGetRtspRealm, _mediaInfo, invoker, static_cast(*this))) { + //无人监听此事件,说明无需认证 + invoker(""); + } + }else{ + invoker(_rtsp_realm); } } void RtspSession::onAuthSuccess() { @@ -725,113 +767,75 @@ void RtspSession::handleReq_Play(const Parser &parser) { send_SessionNotFound(); throw SockException(Err_shutdown,_aTrackInfo.empty() ? "can not find any availabe track when play" : "session not found when play"); } + auto pMediaSrc = _pMediaSrc.lock(); + if(!pMediaSrc){ + send_StreamNotFound(); + shutdown(SockException(Err_shutdown,"rtsp stream released")); + return; + } + + bool useBuf = true; + _enableSendRtp = false; + float iStartTime = 0; auto strRange = parser["Range"]; - auto onRes = [this,strRange](const string &err){ - bool authSuccess = err.empty(); - if(!authSuccess){ - //第一次play是播放,否则是恢复播放。只对播放鉴权 - sendRtspResponse("401 Unauthorized", {"Content-Type", "text/plain"}, err); - shutdown(SockException(Err_shutdown,StrPrinter << "401 Unauthorized:" << err)); + if (strRange.size()) { + //这个是seek操作 + auto strStart = FindField(strRange.data(), "npt=", "-"); + if (strStart == "now") { + strStart = "0"; + } + iStartTime = 1000 * atof(strStart.data()); + InfoP(this) << "rtsp seekTo(ms):" << iStartTime; + useBuf = !pMediaSrc->seekTo(iStartTime); + } else if (pMediaSrc->totalReaderCount() == 0) { + //第一个消费者 + pMediaSrc->seekTo(0); + } + + _StrPrinter rtp_info; + for (auto &track : _aTrackInfo) { + if (track->_inited == false) { + //还有track没有setup + shutdown(SockException(Err_shutdown, "track not setuped")); return; } + track->_ssrc = pMediaSrc->getSsrc(track->_type); + track->_seq = pMediaSrc->getSeqence(track->_type); + track->_time_stamp = pMediaSrc->getTimeStamp(track->_type); - auto pMediaSrc = _pMediaSrc.lock(); - if(!pMediaSrc){ - send_StreamNotFound(); - shutdown(SockException(Err_shutdown,"rtsp stream released")); - return; - } + rtp_info << "url=" << _strContentBase << "/" << track->_control_surffix << ";" + << "seq=" << track->_seq << ";" + << "rtptime=" << (int) (track->_time_stamp * (track->_samplerate / 1000)) << ","; + } - bool useBuf = true; - _enableSendRtp = false; - float iStartTime = 0; - if (strRange.size() && !_bFirstPlay) { - //这个是seek操作 - auto strStart = FindField(strRange.data(), "npt=", "-"); - if (strStart == "now") { - strStart = "0"; - } - iStartTime = 1000 * atof(strStart.data()); - InfoP(this) << "rtsp seekTo(ms):" << iStartTime; - useBuf = !pMediaSrc->seekTo(iStartTime); - }else if(pMediaSrc->totalReaderCount() == 0){ - //第一个消费者 - pMediaSrc->seekTo(0); - } - _bFirstPlay = false; + rtp_info.pop_back(); + sendRtspResponse("200 OK", + {"Range", StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << (useBuf? pMediaSrc->getTimeStamp(TrackInvalid) / 1000.0 : iStartTime / 1000), + "RTP-Info",rtp_info + }); - _StrPrinter rtp_info; - for(auto &track : _aTrackInfo){ - if (track->_inited == false) { - //还有track没有setup - shutdown(SockException(Err_shutdown,"track not setuped")); - return; - } - track->_ssrc = pMediaSrc->getSsrc(track->_type); - track->_seq = pMediaSrc->getSeqence(track->_type); - track->_time_stamp = pMediaSrc->getTimeStamp(track->_type); + _enableSendRtp = true; + setSocketFlags(); - rtp_info << "url=" << _strContentBase << "/" << track->_control_surffix << ";" - << "seq=" << track->_seq << ";" - << "rtptime=" << (int)(track->_time_stamp * (track->_samplerate / 1000)) << ","; - } - - rtp_info.pop_back(); - - sendRtspResponse("200 OK", - {"Range", StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << (useBuf? pMediaSrc->getTimeStamp(TrackInvalid) / 1000.0 : iStartTime / 1000), - "RTP-Info",rtp_info - }); - - _enableSendRtp = true; - setSocketFlags(); - - if (!_pRtpReader && _rtpType != Rtsp::RTP_MULTICAST) { - weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - _pRtpReader = pMediaSrc->getRing()->attach(getPoller(),useBuf); - _pRtpReader->setDetachCB([weakSelf]() { - auto strongSelf = weakSelf.lock(); - if(!strongSelf) { - return; - } - strongSelf->shutdown(SockException(Err_shutdown,"rtsp ring buffer detached")); - }); - _pRtpReader->setReadCB([weakSelf](const RtspMediaSource::RingDataType &pack) { - auto strongSelf = weakSelf.lock(); - if(!strongSelf) { - return; - } - if(strongSelf->_enableSendRtp) { - strongSelf->sendRtpPacket(pack); - } - }); - } - }; - - weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - Broadcast::AuthInvoker invoker = [weakSelf,onRes](const string &err){ - auto strongSelf = weakSelf.lock(); - if(!strongSelf){ - return; - } - strongSelf->async([weakSelf,onRes,err](){ + if (!_pRtpReader && _rtpType != Rtsp::RTP_MULTICAST) { + weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); + _pRtpReader = pMediaSrc->getRing()->attach(getPoller(), useBuf); + _pRtpReader->setDetachCB([weakSelf]() { auto strongSelf = weakSelf.lock(); - if(!strongSelf){ + if (!strongSelf) { return; } - onRes(err); + strongSelf->shutdown(SockException(Err_shutdown, "rtsp ring buffer detached")); + }); + _pRtpReader->setReadCB([weakSelf](const RtspMediaSource::RingDataType &pack) { + auto strongSelf = weakSelf.lock(); + if (!strongSelf) { + return; + } + if (strongSelf->_enableSendRtp) { + strongSelf->sendRtpPacket(pack); + } }); - }; - if(_bFirstPlay){ - //第一次收到play命令,需要鉴权 - auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,_mediaInfo,invoker,static_cast(*this)); - if(!flag){ - //该事件无人监听,默认不鉴权 - onRes(""); - } - }else{ - //后面是seek或恢复命令,不需要鉴权 - onRes(""); } } diff --git a/src/Rtsp/RtspSession.h b/src/Rtsp/RtspSession.h index eadafdff..c7e3160c 100644 --- a/src/Rtsp/RtspSession.h +++ b/src/Rtsp/RtspSession.h @@ -160,6 +160,8 @@ private: void onAuthBasic(const string &realm,const string &strBase64); //校验md5方式的认证加密 void onAuthDigest(const string &realm,const string &strMd5); + //触发url鉴权事件 + void emitOnPlay(); //发送rtp给客户端 void sendRtpPacket(const RtspMediaSource::RingDataType &pkt); @@ -179,8 +181,10 @@ private: string _strContentBase; //Session号 string _strSession; - //是否第一次播放,第一次播放需要鉴权,第二次播放属于暂停恢复 - bool _bFirstPlay = true; + //记录是否需要rtsp专属鉴权,防止重复触发事件 + string _rtsp_realm; + //是否已经触发on_play事件 + bool _emit_on_play = false; //url解析后保存的相关信息 MediaInfo _mediaInfo; //rtsp播放器绑定的直播源