void continueAfterDESCRIBE(RTSPClient* rtspClient, int resultCode, char* resultString) { do { UsageEnvironment& env = rtspClient->envir(); // alias StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias if (resultCode != 0) { env << *rtspClient << "Failed to get a SDP description: " << resultString << "\n"; 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); 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); return; } while (0); // An unrecoverable error occurred with this stream. shutdownStream(rtspClient); }
void setupNextSubsession(RTSPClient* rtspClient) { UsageEnvironment& env = rtspClient->envir(); // alias StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias scs.subsession = scs.iter->next(); if (scs.subsession != NULL) { if (!scs.subsession->initiate()) { env << *rtspClient << "Failed to initiate the \"" << *scs.subsession << "\" subsession: " << env.getResultMsg() << "\n"; setupNextSubsession(rtspClient); // give up on this subsession; go to the next one } else { env << *rtspClient << "Initiated the \"" << *scs.subsession << "\" subsession (client ports " << scs.subsession->clientPortNum() << "-" << scs.subsession->clientPortNum()+1 << ")\n"; // Continue setting up this subsession, by sending a RTSP "SETUP" command: rtspClient->sendSetupCommand(*scs.subsession, continueAfterSETUP); } return; } // We've finished setting up all of the subsessions. Now, send a RTSP "PLAY" command to start the streaming: if (scs.session->absStartTime() != NULL) { // Special case: The stream is indexed by 'absolute' time, so send an appropriate "PLAY" command: rtspClient->sendPlayCommand(*scs.session, continueAfterPLAY, scs.session->absStartTime(), scs.session->absEndTime()); } else { scs.duration = scs.session->playEndTime() - scs.session->playStartTime(); rtspClient->sendPlayCommand(*scs.session, continueAfterPLAY); } }
/*! * \brief Sets up the next subsession which is stored in the scs.subsession object. * * This function sends the rtsp SETUP command to the source and sets up the callback function (continueAfterSETUP) * Changes by the author: If the subsession isn't a MotionJPEG, dismiss it. * \param rtspClient Environment vars */ void setupNextSubsession(RTSPClient* rtspClient) { scs.subsession = scs.iter->next(); std::string result = scs.subsession->mediumName(); //Get the medium name std::string encoding = scs.subsession->codecName(); if ((scs.subsession != NULL) && (result != "audio") && (encoding == "JPEG")) { //We don't want audio. We want JPEG video for now, so ignore the rest if (!scs.subsession->initiate()) { *env << *rtspClient << "Failed to initiate the \"" << *scs.subsession << "\" subsession: " << *env->getResultMsg() << "\n"; setupNextSubsession(rtspClient); // give up on this subsession; go to the next one } else { *env << *rtspClient << "Initiated the \"" << *scs.subsession << "\" subsession (client ports " << scs.subsession->clientPortNum() << "-" << scs.subsession->clientPortNum()+1 << ")\n"; // Continue setting up this subsession, by sending a RTSP "SETUP" command: rtspClient->sendSetupCommand(*scs.subsession, continueAfterSETUP, False, REQUEST_STREAMING_OVER_TCP); // } } return; } // We've finished setting up all of the subsessions. Now, send a RTSP "PLAY" command to start the streaming: if (scs.session->absStartTime() != NULL) { // Special case: The stream is indexed by 'absolute' time, so send an appropriate "PLAY" command: rtspClient->sendPlayCommand(*scs.session, continueAfterPLAY, scs.session->absStartTime(), scs.session->absEndTime()); } else { scs.duration = scs.session->playEndTime() - scs.session->playStartTime(); rtspClient->sendPlayCommand(*scs.session, continueAfterPLAY); } }
void setupNextSubsession(RTSPClient* rtspClient) { UsageEnvironment& env = rtspClient->envir(); // alias StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias scs.subsession = scs.iter->next(); if (scs.subsession != NULL) { if (!scs.subsession->initiate()) { env << *rtspClient << "Failed to initiate the \"" << *scs.subsession << "\" subsession: " << env.getResultMsg() << "\n"; setupNextSubsession(rtspClient); // give up on this subsession; go to the next one } else { // env << *rtspClient << "Initiated the \"" << *scs.subsession // << "\" subsession (client ports " << scs.subsession->clientPortNum() << "-" << scs.subsession->clientPortNum()+1 << ")\n"; // Continue setting up this subsession, by sending a RTSP "SETUP" command: char tranProtocol = ((ourRTSPClient*)rtspClient)->_tranProtocol; rtspClient->sendSetupCommand(*scs.subsession, continueAfterSETUP, false, tranProtocol == 0, tranProtocol == 2); // rtspClient->sendSetupCommand(*scs.subsession, continueAfterSETUP, false, true); } return; } // We've finished setting up all of the subsessions. Now, send a RTSP "PLAY" command to start the streaming: scs.duration = scs.session->playEndTime() - scs.session->playStartTime(); rtspClient->sendPlayCommand(*scs.session, continueAfterPLAY); }
void setupNextSubsession(RTSPClient* rtspClient) { UsageEnvironment& env = rtspClient->envir(); // alias StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias scs.subsession = scs.iter->next(); if (scs.subsession != NULL) { if ( strcmp(scs.subsession->mediumName(),"audio") != 0 || (scs.subsession->getFlag() == 0 && bEnableBackChannel) // flag= 0:receive only 1:send only || !scs.subsession->initiate()) { env << *rtspClient << "Failed to initiate the \"" << *scs.subsession << "\" subsession: " << env.getResultMsg() << "\n"; setupNextSubsession(rtspClient); // give up on this subsession; go to the next one } else { env << *rtspClient << "Initiated the \"" << *scs.subsession << "\" subsession (client ports " << scs.subsession->clientPortNum() << "-" << scs.subsession->clientPortNum()+1 << ")\n"; // 20140625 albert.liao modified start // Continue setting up this subsession, by sending a RTSP "SETUP" command: rtspClient->sendSetupCommand(*scs.subsession, continueAfterSETUP, False, REQUEST_STREAMING_OVER_TCP); // TODO: rtsp server should create PassiveServerMediaSubsession, // so that multicast can work // rtspClient->sendSetupCommand(*scs.subsession, // continueAfterSETUP, // False,//True, /* streamOutgoing, for darwin */ // REQUEST_STREAMING_OVER_TCP, // True, /*Multicast*/ // NULL); // 20140625 albert.liao modified end } return; } //startPlay(rtspClient); shutdownStream(rtspClient); }
void CAimer39RTSPClient::setupNextSubsession(RTSPClient* rtspClient) { UsageEnvironment& env = rtspClient->envir(); // alias StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias CAimer39RTSPClient * arc = findClient( (ourRTSPClient*)rtspClient ); if ( NULL == arc ) { arc->m_errorCode = -1; env << "some how the system in to a dangerous situation!" << "\n"; return; } scs.subsession = scs.iter->next(); if (scs.subsession != NULL) { vector<MediaSubsession *>::iterator iter = arc->m_vecNoNeedStream.begin(); for ( ; iter != arc->m_vecNoNeedStream.end(); ++iter ) { if ( *iter == scs.subsession ) { setupNextSubsession(rtspClient); // give up on this subsession; go to the next one return; } } if (!scs.subsession->initiate()) { env << *rtspClient << "Failed to initiate the \"" << *scs.subsession << "\" subsession: " << env.getResultMsg() << "\n"; arc->m_errorCode = 3; arc->m_lastErrorMsg = env.getResultMsg(); setupNextSubsession(rtspClient); // give up on this subsession; go to the next one } else { env << *rtspClient << "Initiated the \"" << *scs.subsession << "\" subsession (client ports " << scs.subsession->clientPortNum() << "-" << scs.subsession->clientPortNum()+1 << ")\n"; // Continue setting up this subsession, by sending a RTSP "SETUP" command: rtspClient->sendSetupCommand(*scs.subsession, continueAfterSETUP); } return; } // We've finished setting up all of the subsessions. Now, send a RTSP "PLAY" command to start the streaming: if (scs.session->absStartTime() != NULL) { // Special case: The stream is indexed by 'absolute' time, so send an appropriate "PLAY" command: rtspClient->sendPlayCommand(*scs.session, continueAfterPLAY, scs.session->absStartTime(), scs.session->absEndTime()); } else { scs.duration = scs.session->playEndTime() - scs.session->playStartTime(); rtspClient->sendPlayCommand(*scs.session, continueAfterPLAY); } }
void continueAfterSETUP(RTSPClient* rtspClient, int resultCode, char* resultString) { do { UsageEnvironment& env = rtspClient->envir(); // alias StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias if (resultCode != 0) { env << *rtspClient << "Failed to set up the \"" << *scs.subsession << "\" subsession: " << resultString << "\n"; break; } env << *rtspClient << "Set up the \"" << *scs.subsession << "\" subsession (client ports " << scs.subsession->clientPortNum() << "-" << scs.subsession->clientPortNum()+1 << ")\n"; // 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.) // 20140624 albert.liao modified start if(scs.subsession->getFlag()==FLAG_RECVONLY) { //scs.subsession->sink = DummySink::createNew(env, *scs.subsession, rtspClient->url()); scs.subsession->sink = FileSink::createNew(env, "back.pcm"); // 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); } else { //scs.subsession->sink is equal to scs.subsession->fRTPSink; 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 // This sink is created by function MediaSubsession::createSinkObjects scs.subsession->sink->startPlaying(*(scs.subsession->readSource()), subsessionAfterPlaying, scs.subsession); } // 20140624 albert.liao modified end // 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); delete[] resultString; // Set up the next subsession, if any: setupNextSubsession(rtspClient); }
void continueAfterSETUP(RTSPClient* rtspClient, int resultCode, char* resultString) { do { UsageEnvironment& env = rtspClient->envir(); // alias StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias if (resultCode != 0) { env << *rtspClient << "Failed to set up the \"" << *scs.subsession << "\" subsession: " << env.getResultMsg() << "\n"; break; } env << *rtspClient << "Set up the \"" << *scs.subsession << "\" subsession (client ports " << scs.subsession->clientPortNum() << "-" << scs.subsession->clientPortNum()+1 << ")\n"; // 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; } const char* spandPp= scs.subsession->fmtp_spropparametersets(); unsigned int numOfRecords = -1; SPropRecord* rec = parseSPropParameterSets(spandPp, numOfRecords); for (unsigned i = 0; i < numOfRecords; ++i) { unsigned nalUnitSize = rec[i].sPropLength; unsigned char* nalUnitBytes = rec[i].sPropBytes; // this is a byte array, of size "nalUnitSize". // Then do whatever you like with this NAL unit data } 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); // Set up the next subsession, if any: setupNextSubsession(rtspClient); }
void continueAfterSETUP(RTSPClient* rtspClient, int resultCode, char* resultString) { OUTPUT_DEBUG_STRING("%s \n", __FUNCTION__); do { UsageEnvironment& env = rtspClient->envir(); // alias StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias static int SessionID = 0; if (resultCode != 0) { OUTPUT_DEBUG_STRING("Failed to set up the subsession: %s \n", \ resultString); //env << *rtspClient << "Failed to set up the \"" << *scs.subsession << "\" subsession: " << resultString << "\n"; break; } OUTPUT_DEBUG_STRING("Set up the subsession (client ports %u-%u)\n", \ scs.subsession->clientPortNum(), scs.subsession->clientPortNum()+1); //env << *rtspClient << "Set up the \"" << *scs.subsession << "\" subsession (client ports " << scs.subsession->clientPortNum() << "-" << scs.subsession->clientPortNum()+1 << ")\n"; // 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()); OUTPUT_DEBUG_STRING("add = %d, del = %d\n", ++sum_add, sum_del); ((DummySink *)scs.subsession)->SetCallBackFunction(gAVDataFun, gLostDetectFun, SessionID, rtspClient); SessionID ++; // perhaps use your own custom "MediaSink" subclass instead if (scs.subsession->sink == NULL) { OUTPUT_DEBUG_STRING("Failed to create a data sink for the subsession: %s\n", \ env.getResultMsg()); //env << *rtspClient << "Failed to create a data sink for the \"" << *scs.subsession<< "\" subsession: " << env.getResultMsg() << "\n"; break; } OUTPUT_DEBUG_STRING("Created a data sink for the subsession\n"); //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); delete[] resultString; // Set up the next subsession, if any: setupNextSubsession(rtspClient); }
/*! * \brief Sets up the filesink for a rtsp subsession * * This function sets up the filesink for a given rtsp subsession, sets up the callback handler continueAfterPLAY() and sends the PLAY-command to the source (requesting it to start sending data, that is). * As it is only called after filtering all subsessions, it will be only called, if the given subsession is JPEG-encoded. * This ensures that the DBSink inserts only valid data into the DB. * > Changes by the author: Included the build process of a variable camname for saving it in the DB. * > Scheme: cam<camno>.jpeg * * \param rtspClient Environment vars * \param resultCode Result of the rtsp SETUP command * \param resultString Result of the rtsp SETUP command */ void continueAfterSETUP(RTSPClient* rtspClient, int resultCode, char* resultString) { do { if (resultCode != 0) { *env << *rtspClient << "Failed to set up the \"" << *scs.subsession << "\" subsession: " << resultString << "\n"; break; } *env << *rtspClient << "Set up the \"" << *scs.subsession << "\" subsession (client ports " << scs.subsession->clientPortNum() << "-" << scs.subsession->clientPortNum()+1 << ")\n"; // 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.) //Neue Elemente von mir: //Wir bauen uns den Camnamen std::string camprefix = "cam"; std::string camsuffix = ".jpeg"; if(camno == "") camno = "xx"; std::stringstream sstr; sstr << camprefix << camno << camsuffix; scs.subsession->sink = ExtendedFileSink::createNew(*env, sstr.str() , 60000); // Ende Neue Elemente von mir if (scs.subsession->sink == NULL) { *env << *rtspClient << "Failed to create a data sink for the \"" << *scs.subsession << "\" subsession: " << *env->getResultMsg() << "\n"; break; } else *env << "Stream creation succeeded! \n"; *env << *rtspClient << "Created a data sink for the \"" << *scs.subsession << "\" subsession" << "ID: " << scs.subsession->sink->name() << "\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); delete[] resultString; // Set up the next subsession, if any: setupNextSubsession(rtspClient); }
void setupNextSubsession(RTSPClient* rtspClient) { OUTPUT_DEBUG_STRING("%s \n", __FUNCTION__); UsageEnvironment& env = rtspClient->envir(); // alias StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias scs.subsession = scs.iter->next(); if (scs.subsession != NULL) { if (!scs.subsession->initiate()) { //env << *rtspClient << "Failed to initiate the \"" << *scs.subsession << "\" subsession: " << env.getResultMsg() << "\n"; OUTPUT_DEBUG_STRING("Failed to initiate the \" %p \" subsession: %s \n", *scs.subsession, env.getResultMsg()); setupNextSubsession(rtspClient); // give up on this subsession; go to the next one } else { OUTPUT_DEBUG_STRING("Initiated the subsession %p (client ports %u-%u)\n", \ scs.subsession, \ scs.subsession->clientPortNum(), \ scs.subsession->clientPortNum() + 1); //env << *rtspClient << "Initiated the \"" << *scs.subsession << "\" subsession (client ports " << scs.subsession->clientPortNum() << "-" << scs.subsession->clientPortNum()+1 << ")\n"; // Continue setting up this subsession, by sending a RTSP "SETUP" command: Boolean stream_over_tcp = False; if (gStream_Over_Protocol == STREAMING_OVER_TCP) { stream_over_tcp = True; } else if (gStream_Over_Protocol == STREAMING_OVER_UDP) { stream_over_tcp = False; } rtspClient->sendSetupCommand(*scs.subsession, continueAfterSETUP, False, stream_over_tcp); } return; } // We've finished setting up all of the subsessions. Now, send a RTSP "PLAY" command to start the streaming: if (scs.session->absStartTime() != NULL) { // Special case: The stream is indexed by 'absolute' time, so send an appropriate "PLAY" command: rtspClient->sendPlayCommand(*scs.session, continueAfterPLAY, scs.session->absStartTime(), scs.session->absEndTime()); } else { scs.duration = scs.session->playEndTime() - scs.session->playStartTime(); rtspClient->sendPlayCommand(*scs.session, continueAfterPLAY); } }
void CAimer39RTSPClient::continueAfterSETUP(RTSPClient* rtspClient, int resultCode, char* resultString) { do { UsageEnvironment& env = rtspClient->envir(); // alias StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias CAimer39RTSPClient * arc = findClient( (ourRTSPClient*)rtspClient ); if ( NULL == arc ) { env << "some how the system in to a dangerous situation!" << "\n"; break; } arc->m_errorCode = resultCode; if (resultCode != 0) { arc->m_lastErrorMsg = resultString; env << *rtspClient << "Failed to set up the \"" << *scs.subsession << "\" subsession: " << resultString << "\n"; break; } env << *rtspClient << "Set up the \"" << *scs.subsession << "\" subsession (client ports " << scs.subsession->clientPortNum() << "-" << scs.subsession->clientPortNum()+1 << ")\n"; // 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, arc, 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); delete[] resultString; // Set up the next subsession, if any: setupNextSubsession(rtspClient); }
int CAimer39RTSPClient::Play() { // 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.) m_pRTSPClient->scs.iter = new MediaSubsessionIterator(*(m_pRTSPClient->scs.session)); setupNextSubsession( m_pRTSPClient ); m_bIsPlay = true; m_nRecvBytes = 0; m_nRecvVideoBytes = 0; timeval stTime = {0}; m_StaticClock.start(stTime); return m_errorCode; }
void continueAfterSETUP(RTSPClient* rtspClient, int resultCode, char* resultString) { (void)resultString; do { UsageEnvironment& env = rtspClient->envir(); // alias StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias if (resultCode != 0) { env << *rtspClient << "Failed to set up the \"" << *scs.subsession << "\" subsession: " << env.getResultMsg() << "\n"; break; } // env << *rtspClient << "Set up the \"" << *scs.subsession //<< "\" subsession (client ports " << scs.subsession->clientPortNum() << "-" << scs.subsession->clientPortNum()+1 << ")\n"; // 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; } ourRTSPClient* ourClient = (ourRTSPClient*)rtspClient; DummySink* ourSink = (DummySink*)scs.subsession->sink; ourSink->SetDataCallback(ourClient->_channel, ourClient->_cb); // 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); // Set up the next subsession, if any: setupNextSubsession(rtspClient); }
void setupNextSubsession(RTSPClient* rtspClient) { UsageEnvironment& env = rtspClient->envir(); // alias StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias scs.subsession = scs.iter->next(); if (scs.subsession != NULL) { if (!scs.subsession->initiate()) { env << *rtspClient << "Failed to initiate the \"" << *scs.subsession << "\" subsession: " << env.getResultMsg() << "\n"; setupNextSubsession(rtspClient); // give up on this subsession; go to the next one } else { env << *rtspClient << "Initiated the \"" << *scs.subsession << "\" subsession (client ports " << scs.subsession->clientPortNum() << "-" << scs.subsession->clientPortNum()+1 << ")\n"; // 20140625 albert.liao modified start // Continue setting up this subsession, by sending a RTSP "SETUP" command: rtspClient->sendSetupCommand(*scs.subsession, continueAfterSETUP, False, REQUEST_STREAMING_OVER_TCP); // TODO: rtsp server should create PassiveServerMediaSubsession, // so that multicast can work // rtspClient->sendSetupCommand(*scs.subsession, // continueAfterSETUP, // False,//True, /* streamOutgoing, for darwin */ // REQUEST_STREAMING_OVER_TCP, // True, /*Multicast*/ // NULL); // 20140625 albert.liao modified end } return; } // We've finished setting up all of the subsessions. Now, send a RTSP "PLAY" command to start the streaming: if (scs.session->absStartTime() != NULL) { // Special case: The stream is indexed by 'absolute' time, so send an appropriate "PLAY" command: rtspClient->sendPlayCommand(*scs.session, continueAfterPLAY, scs.session->absStartTime(), scs.session->absEndTime()); } else { scs.duration = scs.session->playEndTime() - scs.session->playStartTime(); rtspClient->sendPlayCommand(*scs.session, continueAfterPLAY); } }
void continueAfterSETUP(RTSPClient* rtspClient, int resultCode, char* resultString) { do { UsageEnvironment& env = rtspClient->envir(); // alias StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias if (resultCode != 0) { env << *rtspClient << "Failed to set up the \"" << *scs.subsession << "\" subsession: " << resultString << "\n"; break; } env << *rtspClient << "Set up the \"" << *scs.subsession << "\" subsession (client ports " << scs.subsession->clientPortNum() << "-" << scs.subsession->clientPortNum()+1 << ")\n"; const char *sprop = scs.subsession->fmtp_spropparametersets(); uint8_t const* sps = NULL; unsigned spsSize = 0; uint8_t const* pps = NULL; unsigned ppsSize = 0; if (sprop != NULL) { unsigned numSPropRecords; SPropRecord* sPropRecords = parseSPropParameterSets(sprop, numSPropRecords); for (unsigned i = 0; i < numSPropRecords; ++i) { if (sPropRecords[i].sPropLength == 0) continue; // bad data u_int8_t nal_unit_type = (sPropRecords[i].sPropBytes[0])&0x1F; if (nal_unit_type == 7/*SPS*/) { sps = sPropRecords[i].sPropBytes; spsSize = sPropRecords[i].sPropLength; } else if (nal_unit_type == 8/*PPS*/) { pps = sPropRecords[i].sPropBytes; ppsSize = sPropRecords[i].sPropLength; } } } // 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 if (sps != NULL) { ((DummySink *)scs.subsession->sink)->setSprop(sps, spsSize); } if (pps != NULL) { ((DummySink *)scs.subsession->sink)->setSprop(pps, ppsSize); } 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); delete[] resultString; // Set up the next subsession, if any: setupNextSubsession(rtspClient); }