/**********
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2.1 of the License, or (at your
option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
more details.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
**********/
// Copyright (c) 1996-2014, Live Networks, Inc. All rights reserved
// A demo application, showing how to create and run a RTSP client (that can potentially receive multiple streams concurrently).
//
// NOTE: This code - although it builds a running application - is intended only to illustrate how to develop your own RTSP
// client application. For a full-featured RTSP client application - with much more functionality, and many options - see
// "openRTSP": http://www.live555.com/openRTSP/
#include "RTSPClientLib.h"
#include "BasicTaskSchedulerEpoll.h"
void TaskExitRTSP( void * clientData )
{
ourRTSPClient* rtspclient = (ourRTSPClient*)clientData;
shutdownStream(rtspclient, 0);
}
void TaskKeepAliveRTSP( void * clientData )
{
ourRTSPClient* rtspclient = (ourRTSPClient*)clientData;
//printf("TaskKeepAliveRTSP---send options \n");
rtspclient->sendOptionsCommand(KeepRTSPAliveAfterOptions,rtspclient->pAuthenticator);
}
void KeepRTSPAliveAfterOptions(RTSPClient* rtspClient, int resultCode, char* resultString)
{
((ourRTSPClient*)rtspClient)->i_live555_ret = resultCode ;
do
{
UsageEnvironment& env = rtspClient->envir(); // alias
//StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias
if (resultCode != 0) {
env << *rtspClient <<"Thread["<< ((ourRTSPClient*)rtspClient)->i_thread_no \
<< "] KeepRTSPAliveAfterOptions -- resultCode =[ "<< resultCode << "] Failed to OPTIONS : " << resultString << "\n";
if ( resultString != NULL)
delete[] resultString;
//have error then stop receive data
((ourRTSPClient*)rtspClient)->eventLoopWatchVariable=1;
break ;
}
else
{
// char* const getOptions = resultString;
// env << *rtspClient << "Got Server getOptions:\n" << getOptions << "\n\n\n";
if ( resultString != NULL)
delete[] resultString;
//network is normal,reset task
//printf("KeepRTSPAliveAfterOptions----reset task\n");
((ourRTSPClient*)rtspClient)->keepAliveTask = env.taskScheduler().scheduleDelayedTask( KEEP_RTSP_ALIVE_TIMEOUT,
TaskKeepAliveRTSP,
(ourRTSPClient*)rtspClient);
return ;
}
}
while(0);
}
//call back after process options command
void continueAfterOPTIONS(RTSPClient* rtspClient, int resultCode, char* resultString)
{
do{
UsageEnvironment& env = rtspClient->envir(); // alias
//StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias
((ourRTSPClient*)rtspClient)->i_live555_ret = resultCode ;
if (resultCode != 0)
{
env << *rtspClient <<"Thread["<< ((ourRTSPClient*)rtspClient)->i_thread_no<< "] Failed to OPTIONS : " << resultString << "\n";
if ( resultString != NULL)
delete[] resultString;
break;
}
char* const getOptions = resultString;
//env << *rtspClient << "Got Server getOptions:\n" << getOptions << "\n\n\n";
if ( getOptions != NULL)
delete[] getOptions;
//rtspClient->sendDescribeCommand(continueAfterDESCRIBE, ((ourRTSPClient*)rtspClient)->pAuthenticator);
rtspClient->sendDescribeCommand(continueAfterDESCRIBE);
return ;
}while(0);
shutdownStream(rtspClient);
}
//call back after process describe command
void continueAfterDESCRIBE(RTSPClient* rtspClient, int resultCode, char* resultString)
{
do {
UsageEnvironment& env = rtspClient->envir(); // alias
StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias
((ourRTSPClient*)rtspClient)->i_live555_ret = resultCode ;
if (resultCode != 0)
{
env << *rtspClient <<"Thread["<< ((ourRTSPClient*)rtspClient)->i_thread_no<< "] Failed to get a SDP description: " << resultString << "\n";
delete[] resultString;
break;
}
char* const sdpDescription = resultString;
//env << *rtspClient << "Got a SDP description:\n" << sdpDescription << "\n";
// Create a media session object from this SDP description:
scs.session = MediaSession::createNew(env, sdpDescription);
if( sdpDescription != NULL )
delete[] sdpDescription; // because we don't need it anymore
if (scs.session == NULL) {
env << *rtspClient << "Failed to create a MediaSession object from the SDP description: " << env.getResultMsg() << "\n";
break;
} else if (!scs.session->hasSubsessions()) {
env << *rtspClient << "This session has no media subsessions (i.e., no \"m=\" lines)\n";
break;
}
// Then, create and set up our data source objects for the session. We do this by iterating over the session's 'subsessions',
// calling "MediaSubsession::initiate()", and then sending a RTSP "SETUP" command, on each one.
// (Each 'subsession' will have its own data source.)
scs.iter = new MediaSubsessionIterator(*scs.session);
setupNextSubsession(rtspClient);
((ourRTSPClient*)rtspClient)->KeepRTSPAlive(&(env.taskScheduler()));
return;
} while (0);
// An unrecoverable error occurred with this stream.
shutdownStream(rtspClient);
}
//call back after process setup command
void continueAfterSETUP(RTSPClient* rtspClient, int resultCode, char* resultString)
{
do {
UsageEnvironment& env = rtspClient->envir(); // alias
StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias
((ourRTSPClient*)rtspClient)->i_live555_ret = resultCode ;
if (resultCode != 0)
{
env << *rtspClient <<"Thread["<< ((ourRTSPClient*)rtspClient)->i_thread_no<< "] Failed to set up the \"" << *scs.subsession << "\" subsession: " << resultString << "\n";
/*
if ( resultString != NULL)
delete[] resultString;
*/
break;
}
// Having successfully setup the subsession, create a data sink for it, and call "startPlaying()" on it.
// (This will prepare the data sink to receive data; the actual flow of data from the client won't start happening until later,
// after we've sent a RTSP "PLAY" command.)
scs.subsession->sink = DummySink::createNew(env, *scs.subsession, rtspClient->url());
// perhaps use your own custom "MediaSink" subclass instead
if (scs.subsession->sink == NULL) {
env << *rtspClient << "Failed to create a data sink for the \"" << *scs.subsession
<< "\" subsession: " << env.getResultMsg() << "\n";
break;
}
env << *rtspClient << "Created a data sink for the \"" << *scs.subsession << "\" subsession\n";
scs.subsession->miscPtr = rtspClient; // a hack to let subsession handle functions get the "RTSPClient" from the subsession
scs.subsession->sink->startPlaying(*(scs.subsession->readSource()),
subsessionAfterPlaying, scs.subsession);
// Also set a handler to be called if a RTCP "BYE" arrives for this subsession:
if (scs.subsession->rtcpInstance() != NULL) {
scs.subsession->rtcpInstance()->setByeHandler(subsessionByeHandler, scs.subsession);
}
} while (0);
if ( resultString != NULL)
delete[] resultString;
//