[Live-devel] controlling the rtsp negotiation with custom event loop

Sampsa Riikonen sampsa.riikonen at iki.fi
Fri Dec 18 04:24:54 PST 2015



On 17.12.2015 17:46, Ross Finlayson wrote:
>> I have an application that has its own event loop when manipulating/reading sockets, however, I'd like to use live555 to do the rtsp negotiation process with the cameras.
> Unfortunately, I’m not quite sure what you mean when you say that your application “has its own event loop when manipulating/reading sockets”, because the LIVE555 code - when it implements RTSP/RTP/RTCP - does so by ‘reading and writing sockets’.  Therefore, if you want to implement RTSP/RTP/RTCP using the “LIVE555 Streaming Media” code, then you *must* do so using the LIVE555 event loop, which you will enter by calling “doEventLoop()” within your application.
>
> Perhaps your application already has its own event loop (e.g., to implement a GUI)?  In that case, you *could* try to arrange for these other ‘GUI’ events to be handled as part of the LIVE555 event loop - i.e., so that your application has just a single event loop.  Most people, however, find it simpler to run all of the LIVE555 code (including its event loop) in a separate thread, with the other ‘main’ event loop thread communicating with the LIVE555 event loop thread via shared variables (e.g. event loop ‘watch variables’) or by calling “triggerEvent()” (the *only* LIVE555 function that you may call from the non-LIVE555 event loop thread).
>
>
>> I also need my own step-to-step control over the rtsp negotiation process, i.e.
>>
>> 1) describe+setup => port numbers
>> (do something within my own event loop)
>> 2) play
>> (do something within my own event loop)
>> 3) teardown
>> (do something within my own event loop)
> This is easy to do - except that instead of doing ‘something’ within your ‘own' event loop, you will do it within the LIVE555 event loop.  Note that each LIVE555 function that implements the sending of a RTSP command - i.e., “sendDescribeCommand()”, “sendSetupCommand()”, “sendPlayCommand()” etc. - takes, as a parameter, a function that will get called, automatically (by the LIVE555 event loop), after the RTSP command has completed.  It is within this function that you would do your ‘something’ in each case.

Dear Ross,

Thank you for your reply.  The long story is, that I have my own program 
having its own event loop, with simultaneous select calls on sockets, 
multiprocessing pipes, etc.

In the future, I will migrate my code into using live555, but I can't do 
it in one shot..!  (always been a bit slow learner..)

At the moment I'd like to use the live555 rtsp implementation to do the 
authentication and negotiation part.. after getting the port numbers, I 
will open the sockets for udp streaming myself and use my own existing 
code..

.. yes, sounds stupid, but that is the fix for the moment (my own rtsp 
negotiation code fails with some cameras needing stronger authentication 
methods.. and I don't want to reinvent the wheel (once) again).. as I'll 
learn more live555, I'll do the (semi/complete) migration to it.

>> 1) I understand that in the rtsp "response handlers" and in the callbacks within them, we create the necessary logic, but how does the program actually run?  .. does the event loop explicitly execute the "response handlers"..? where in the code this takes place?
> All of this (the LIVE555 event loop) takes place inside the call to “doEventLoop()”; see
> 	http://live555.com/liveMedia/faq.html#control-flow
> The LIVE555 code handles each RTSP response by handling a ‘new data is available’ event on the RTSP command socket.  In doing so, it will read and parse the RTSP response, and call the appropriate ‘response handler’.  It does all of this automatically (within the LIVE555 event loop), and you don’t need to concern yourself with how this is implemented (i.e., you should treat the LIVE555 libraries as being a ‘black box’).

Thanks for the explanation..!   Let's see if I have understood correctly 
by looking at the "testRTSPClient.cpp:"  intendation means entering a 
function/method

main:

   => openURL

     => rtspClient->sendDescribeCommand(continueAfterDESCRIBE) [1]
       => continueAfterDESCRIBE(rtspClient,..): 
setupNextSubSession(rtspClient) [2]
         => rtspClient->sendSetupCommand(*scs.subsession, 
continueAfterSETUP, ..) [3]
           => continueAfterSETUP(rtspClient,..): [4]
             => scs.subsession->sink = DummySink::createNew(env, 
*scs.subsession, rtspClient->url());
             => 
scs.subsession->sink->startPlaying(*(scs.subsession->readSource()), 
subsessionAfterPlaying, scs.subsession);
         => rtspClient->sendPlayCommand(*scs.session, continueAfterPLAY, 
..) [5]

   => start the event loop [6]

Also, let's keep in mind:

rtspClient->envir() gives the UsageEnvironment
rtspClient->envir()->taskScheduler() gives the taskScheduler

[1] registers a command to the event loop.  The method is found in 
"RTSPClient.cpp":

sendDescribeCommand(responseHandler* responseHandler, Authenticator* 
authenticator)
  return sendRequest(new RequestRecord(++fCSeq, "DESCRIBE", 
responseHandler));

[2] does not register anything to the event loop, but simply sets up a 
logic with the callback functions

etc.

[6] event loop executes the first command that has been registered 
(somehow.. with "RequestRecord" ?) into it
.. which results in a cascade execution of the callback functions, i.e. 
"continueAfterDESCRIBE", etc.

The next thing the event loop handles, is "sendSetupCommand"

In general, all of these "send*Command"s are registered into, and 
executed one by one by the event loop, while each execution goes into a 
cascade of callbacks.

.. ummm, right?

Could you maybe give me a clue, where in the code is the registration of 
events to the event loop implemented..?


>
>> 3) Is there any better way to access the subsession data, other than always creating a *new* MediaSubsessionIterator and then using the "next()" method ?  .. iterators should have also "begin()", "previous()", etc. methods, but these seem to me missing in the code..?  i.e. one must create a new object and then, after using "next" couple of times, the object becomes useless and throwing segfaults if you try to access data, for example, clientPortNums.
> I don’t really understand what you’re asking here, but I don’t think you understand how the “testRTSPClient” code (for example) works.  Note, in particular, how this code defines a class “StreamClientState”, which includes a “MediaSubsessionIterator” and a pointer to a “MediaSubsession”.  An object of this class is used to represent the current state of the RTSP client.  Note that a “MediaSubsessionIterator” is created only once (for each RTSP client).

After the rtsp negotiation, the data about the media subsessions is 
available .. I just wanted a way to access that data in a convenient way 
(and to use it outside the event loop).

Thanks for the great code.. and for your patience..!  ;)

Regards,

Sampsa

>
>
> Ross Finlayson
> Live Networks, Inc.
> http://www.live555.com/
>
>
> _______________________________________________
> live-devel mailing list
> live-devel at lists.live555.com
> http://lists.live555.com/mailman/listinfo/live-devel



More information about the live-devel mailing list