1、 最近在做项目的过程中遇到一个问题,在用Darwin Streaming Server中的QTSSReflectorModule模块做为流转发和分发服务,用live555的DarwinInjector类做为模拟设备 进行流推送时,如果按照正常RTSP推送流程:Announce、Setup、Play…、Teardown,Darwin能较好地完成流的转发,但是假如设备在不正常工作,例如网络异常断开,设备断电等中断了数据流的推送,而缺少了<设备->服务器>的Teardown过程,这样与此路推送相关的RTSPSession、RTPSession以及ReflectorSession等都需要等到配
2、置的“rtp_timeout”时间后、RTPSession超时才能析构所有相关转发对象。先分析下原因: RTSPSession在创建RTPSession时 [cpp] view plaincopyprint? 1. // Set the current RTSP session for this RTP session. 2. // We do this here because we need to make sure the SessionMutex 3. // is grabbed while we do this. Only do this if th
3、e RTSP session 4. // is still alive, of course. 5. if (this->IsLiveSession()) 6. fRTPSession->UpdateRTSPSession(this); // Set the current RTSP session for this RTP session. // We do this here because we need to make sure the SessionM
4、utex // is grabbed while we do this. Only do this if the RTSP session // is still alive, of course. if (this->IsLiveSession()) fRTPSession->UpdateRTSPSession(this); [cpp] view plaincopyprint?
5、1. void RTPSessionInterface::UpdateRTSPSession(RTSPSessionInterface* inNewRTSPSession) 2. { 3. if (inNewRTSPSession != fRTSPSession) 4. { 5. // If there was an old session, let it know that we are done 6. if (fRTSPSession != NULL) 7. fRTSPSes
6、sion->DecrementObjectHolderCount(); 8. 9. // Increment this count to prevent the RTSP session from being deleted 10. fRTSPSession = inNewRTSPSession; 11. fRTSPSession->IncrementObjectHolderCount(); 12. } 13. } void RTPSessionInterface::Updat
7、eRTSPSession(RTSPSessionInterface* inNewRTSPSession) { if (inNewRTSPSession != fRTSPSession) { // If there was an old session, let it know that we are done if (fRTSPSession != NULL) fRTSPSession->DecrementObjectHolderCount(); // Increme
8、nt this count to prevent the RTSP session from being deleted fRTSPSession = inNewRTSPSession; fRTSPSession->IncrementObjectHolderCount(); } } IncrementObjectHolderCount()增加了fRTPSession对RTSPSession的引用,而对应的DecrementObjectHolderCount()在RTPSession::Teardown()中执行,由于RTSPSession拥
9、有很好的对象保护机制,只有当对当前RTSPSession的引用数为0时 [cpp] view plaincopyprint? 1. // Only delete if it is ok to delete! 2. if (fObjectHolders == 0) 3. return -1; // Only delete if it is ok to delete! if (fObjectHolders == 0) return -1; RTSPSession自身才能调用Task::Run(){return -1;} d
10、elete,所以在RTSPSession注销之前,必须等待RTPSession注销,而且RTPSession没有等到Teardown命令,就只能等超时,而这个超时时间不能定,及时几秒钟对于转发实时流来说也是不合理的。 解决办法: 在RTSPSession:Run()函数中的 [cpp] view plaincopyprint? 1. while(IsLiveSession()) 2. { 3. switch(){case:} 4. } while(IsLiveSession()) { switch(){case:} } 状态机
11、外加入代码及时析构RTPSession [cpp] view plaincopyprint? 1. // Make absolutely sure there are no resources being occupied by the session 2. // at this point. 3. this->CleanupRequest(); 4. 5. 6. //Kill与RTSPSession相关的RTPSession 7. if(!IsLiveSession()){ 8. OSRefTable* theMap = QTSServ
12、erInterface::GetServer()->GetRTPSessionMap(); 9. OSRef* theRef = theMap->Resolve(&fLastRTPSessionIDPtr); 10. if (theRef != NULL){ 11. fRTPSession = (RTPSession*)theRef->GetObject(); 12. if(fRTPSession) fRTPSession->Teardown(); 13. theMap->Release(fRTPSession->GetRef());
13、 14. fRTPSession = NULL; 15. } 16. } 17. // Only delete if it is ok to delete! 18. if (fObjectHolders == 0) return -1; 19. // If we are here because of a timeout, but we can't delete because someone 20. // is holding onto a reference to this session,
14、 just reschedule the timeout. 21. // At this point, however, the session is DEAD. 22. return 0; // Make absolutely sure there are no resources being occupied by the session // at this point. this->CleanupRequest(); //Kill与RTSPSession相关的RTPSession if(!IsLiveSession()){
15、 OSRefTable* theMap = QTSServerInterface::GetServer()->GetRTPSessionMap(); OSRef* theRef = theMap->Resolve(&fLastRTPSessionIDPtr); if (theRef != NULL){ fRTPSession = (RTPSession*)theRef->GetObject(); if(fRTPSession) fRTPSession->Teardown(); theMap->Release(fRTPSession->GetRef()); fRT
16、PSession = NULL; } } // Only delete if it is ok to delete! if (fObjectHolders == 0) return -1; // If we are here because of a timeout, but we can't delete because someone // is holding onto a reference to this session, just reschedule the timeout. // At this poi
17、nt, however, the session is DEAD. return 0; 注意 this->CleanupRequest();在前, 这样就能在RTSPSession判断fObjectHolders之前将附属的RTPSession析构,进而析构RTSPSession. 由于工作比较忙,写的可能在思路上不是很清楚,欢迎指正! /--------------------------------------割了------------------------------------/ 在上段代码中可以加入一个补充条件进行代码的优化,并且CleanupReques
18、t()必须在此之后! [cpp] view plaincopyprint? 1. //fObjectHolders-- 2. if(!IsLiveSession()&& fObjectHolders > 0){ 3. OSRefTable* theMap = QTSServerInterface::GetServer()->GetRTPSessionMap(); 4. OSRef* theRef = theMap->Resolve(&fLastRTPSessionIDPtr); 5. if (theRef != NULL){ 6.
19、 fRTPSession = (RTPSession*)theRef->GetObject(); 7. if(fRTPSession) fRTPSession->Teardown(); 8. theMap->Release(fRTPSession->GetRef()); 9. fRTPSession = NULL; 10. } 11. } 12. 13. // Make absolutely sure there are no resources being occupied by the session 14. // at this point. 15. this->CleanupRequest(); 16. 17. // Only delete if it is ok to delete! 18. if (fObjectHolders == 0) 19. return -1;






