[Live-devel] ByteStreamFileSource closing pipe file descriptor

Wiser, Tyson TWiser at logostech.net
Tue Sep 8 07:19:57 PDT 2015


I forget the specific motivation behind this API change (which occurred back in 2011), but I suspect it had to do with wanting to make sure that open files are never left lying around once the “ByteStreamFileSource” object is closed.

I can understand that, but that could have been achieved with the old API when deleteFidOnClose was true. If it was false instead, then the user was specifically telling you that it was the user’s responsibility to make sure the fid was closed.

 I’m able to get around this by checking for a clientSessionId of 0 in my SubclassOnDemandServerMediaSubsession::createNewStreamSource() function. In this case I don’t use the real file descriptor, but this seems like a hack to me.  Is there a better way to prevent my file descriptor from getting closed before I want it to?

Not that I can tell, because closing the “ByteStreamFileSource” object now always closes the fid.  (Again, I’m not sure why the “deleteFidOnClose” parameter got removed, but there must have been a good reason for this at the time :-)

I’m sure there was a good reason. I’ve been on the list long enough to know that you always have good reasons for making your code changes.

An alternative would be for you to actually handle the ‘broken pipe’ signal in your other thread, by tearing down its end of the pipe.  (And, then, you’d get to create the pipe a second time, for the ‘real’ (i.e. “clientSessionId != 0”) stream.)  In fact, you probably want to do this signal handling anyway, to handle the case when the ‘real’ stream gets closed - e.g., if your last RTSP client does a RTSP “TEARDOWN” on it.  Since you need to do this anyway, you might as well do it also for the “clientSessionId == 0” case, if it’s not too inefficient to do so.

I agree that this sounds like a good solution in theory, but I don’t know that it can work in practice without resorting to what feels to me like hacks.  Consider the following.

MyServer is a multithreaded class that manages the RTSP server as well as a thread that generates the H264 video. There is only a single source of live video and the reuseFirstSource flag is always set to true.  When MyServer starts up, it does its initialization, including creating the pipe used for communication between the RTSP and video production threads, starts the video production thread and then the main thread becomes the RTSP thread.  In the RTSP thread it sets up the task scheduler, usage environment, RTSP server, ServerMediaSession, ServerMediaSubsession, and then enters the scheduler’s event loop.  As mentioned before, the ServerMediaSubsession object is a sub-classed OnDemandServerMediaSubsession that passes the pipe fid to a ByteStreamFileSource.

When a client connects to the RTSP server, it sends a DESCRIBE message, which triggers the creation of the temporary ByteStreamFileSource.  As expected, the deletion of this temporary object closes the pipe fid.  The client then sends SETUP and PLAY messages.  The SETUP message triggers the creation of the actual ByteStreamFileSource object using the (already closed) pipe fid.  The PLAY message triggers the video production thread to actually produce video (no point in doing useless work if no client is playing), so it tries to write to the pipe.  Since I have never attempted to write to the pipe until this point, it is only now that I can notice (either through SIGPIPE or EPIPE) that the read end of the pipe was closed, but it is now too late to give the ByteStreamFileSource object a new fid as that is set in the constructor (through the createNew() function).  The only way I can see to change the fid when needed would be to sub-class ByteStreamFileSource and expose methods to allow the protected fFid field to be changed, but that seems like a hack to me and I’m not sure what other implications that may have.

As an aside, you could, if you wish, eliminate the ‘broken pipe’ signal by calling our
            ignoreSigPipeOnSocket()       (defined in “groupsock/include/GroupsockHelper.hh”)
function on the socket (i.e., at the LIVE555-thread end of the pipe).  But in your case, you probably don’t want to do this, unless you have some other way of telling your non-LIVE555 thread that it needs to close its end of the pipe.

Something somewhere is already ignoring SIGPIPE and I check for EPIPE on the write() call instead.  Either way, both are only generated after a call to write().  As noted above, this is too late to be able to pass a new pipe fid to the ByteStreamFileSource instance, unless there is something that I am missing.

I’m not necessarily asking for you to change the API back to how it was; as you said, there was probably a good reason for changing it in the first place.  I was hoping, however, that you or someone else on the list would have a clean an elegant solution.  If not, I’ll stick with my hack of checking the clientSessionId (assuming this is guaranteed to be non-zero if there is an actual session).  Alternatively, if I have enough time (haha), I could change my code to have the OnDemandServerMediaSubsession sub-class create the pipe when a new stream source was created and then signal the other thread to close its old fid and start using the new one instead.

Thanks,
Tyson


Ross Finlayson
Live Networks, Inc.
http://www.live555.com/

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.live555.com/pipermail/live-devel/attachments/20150908/618a1092/attachment.html>


More information about the live-devel mailing list