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