[Live-devel] Live555 RTSP Client never sees RTCP BYE message from Live555 Server

Matt Schuckmann matt at schuckmannacres.com
Wed Mar 11 10:02:06 PDT 2009


I understand that it's hard to test bugs on modified code, I'd submit my 
modifications to the project but you've already told me that you won't 
accept some of them (I understand your reasons), and I'm not ready to 
submit the others. I'm only trying to help you out by reporting what I 
see, I haven't changed any of the code in the areas I'm referring to here.

I'm pretty sure that this would happen with unmodified code, just see if 
your bye handler is called in OpenRTSP after sending or a teardown 
message while the source is still playing. Or better yet stick a network 
sniffer on a test setup and you'll see the server never sends the bye 
message after receiving a teardown from the client.

Also note the call sequence when the server is tearing things down:
The server deletes the clientSession which causes reclaimStreamStates to 
be called which causes OnDemandServerMediaSubsession::deleteStream().
The first thing OnDemandServerMediaSubsession::deleteStream() does is 
call StreamState::endPlaying() on the streamState with destination 
addresses to stop playing for.
End playing removes the destinations from the groupSock associated with 
the RTCPInstance object.
OnDemandServerMediaSubsession::deleteStream() goes through and 
decrements the refcounts for all the streamStates and deletes all the 
streamState's with a reference count of 0 (which a unicast session is 
all of them). The destructor for the streamState objects calls 
StreamState::reclaim which calls Medium::close() for the RTCPinstance , 
which deletes the RTCPInstance. The destructor for RTCPInstance calls 
SendBYE() which on the surface appears to work but in fact doesn't do 
anything at all, because all the destinations in the groupsock have been 
removed already so the BYE message never gets sent to the server.
Make sense?

Ross Finlayson wrote:
> In general, it's hard to respond to alleged bug reports on modified 
> code.  The best bug reports are those that apply to the original, 
> unmodified code, so we can (hopefully) reproduce the problem (if any) 
> ourselves.
>
>
>> PS. You also should note that the BYE handler code in OpenRTSP causes 
>> all the streams to be deleted and the RTCPInstance objects with them, 
>> the problem is the RTCPInstance object is in the process of handling 
>> a packet.
>
> Remember that this is all single-threaded code.  If an "RTCPInstance" 
> object is deleted, then it's not also 'in the process' of doing 
> anything else.  The only way it could also be involved in 'handling a 
> packet' would be if this packet handling happened later, as a result 
> of an 'incoming packet' event in the event loop.  But that should 
> never happen, because - as a result of deleting the "RTCPInstance" 
> object - "TaskScheduler::turnOffBackgroundReadHandling()" gets called.

I'm very aware that it's single threaded and I've made sure to work 
within that context. The fact that it's a single thread library doesn't 
preclude one from calling delete from within one of that objects 
methods, or worse yet while such a method is on the call stack, which is 
the case here.

If you look at the BYE case in RTCPInstance::incomingReportHandler1() 
you see that the byeHandler is called on or about line 522 (I've changed 
all the fprintf's to calls to envir() << to improve debugging in a non 
command line app, so my line numbers might not match yours, that's the 
only change I've made to this code).
If you follow the call sequence for OpenRTSP you'll see that this 
becomes a call to subsessionByeHandler in PlayCommon.cpp,  If all the 
subsessions have been stopped subsesionByeHandler() then calls 
sessionAfterPlaying() (also in PlayCommon.cpp).  The 
sessionAfterPlaying() function then calls Shutdown() which calls 
closeMediaSinks() and tearDownStreams() , and closes the session before 
calling exit(). It think it's closeMediaSink() or tearDownStreams() that 
causes all the streams and there respective RTCPInstance's to be 
deleted. Now if you remove the call to exit() you'd see that eventually 
the call stack will unwind all the way back up to 
RTCPInstance::incomingReportHandler1() which oops the object associated 
with this call has been deleted so if any of the execution after the 
call the ByeHandler tries to use the any of that objects state you'll be 
in trouble. That's what I mean by the RTCPInstance is deleted while it's 
in the process of handling the BYE message. I generally consider it bad 
form to call delete on a object while one of it's methods are on the 
call stack.  In this particular case I don't think that 
RTCPInstance::incomingReportHandler1() should be changed it's, it can't 
know that a client is going to want to delete it, in fact it should 
assume that it won't. More likely OpenRTSP should be changed to clean 
things up outside of the call sequence origonating from it's byeHandler.
My case I just scheduled a delayed task with the taskScheduler to do the 
clean up.

I discovered this when:
1. I got the server to send BYE messages by adding a call to SendBYE as 
I described before.
2. I changed all the fprintf's in RTCPInstance to envir() << and my app 
would crash when RTCPInstance::incomingReportHandler1() would try to log 
something after the call to the byeHandler.

I hope this all makes sense and it helps you and other users of this 
very useful library out.

Matt S.


More information about the live-devel mailing list