示例#1
0
Boolean AVIFileSink::continuePlaying() {
  // Run through each of our input session's 'subsessions',
  // asking for a frame from each one:
  Boolean haveActiveSubsessions = False;
  MediaSubsessionIterator iter(fInputSession);
  MediaSubsession* subsession;
  while ((subsession = iter.next()) != NULL) {
    FramedSource* subsessionSource = subsession->readSource();
    if (subsessionSource == NULL) continue;

    if (subsessionSource->isCurrentlyAwaitingData()) continue;

    AVISubsessionIOState* ioState
      = (AVISubsessionIOState*)(subsession->miscPtr);
    if (ioState == NULL) continue;

    haveActiveSubsessions = True;
    unsigned char* toPtr = ioState->fBuffer->dataEnd();
    unsigned toSize = ioState->fBuffer->bytesAvailable();
    subsessionSource->getNextFrame(toPtr, toSize,
				   afterGettingFrame, ioState,
				   onSourceClosure, ioState);
  }
  if (!haveActiveSubsessions) {
    envir().setResultMsg("No subsessions are currently active");
    return False;
  }

  return True;
}
示例#2
0
void ProxyRTSPClient::checkInterPacketGaps_() {
  if (fInterPacketGapMaxTime == 0) return; // we're not checking

  // Check each subsession, counting up how many packets have been received:
  unsigned newTotNumPacketsReceived = 0;

  MediaSubsessionIterator iter(*fOurServerMediaSession.fClientMediaSession);
  MediaSubsession* subsession;
  while ((subsession = iter.next()) != NULL) {
    RTPSource* src = subsession->rtpSource();
    if (src == NULL) continue;
    newTotNumPacketsReceived += src->receptionStatsDB().totNumPacketsReceived();
  }

  //envir() << *this << "::doLivenessCheck fTotNumPacketsReceived: " << fTotNumPacketsReceived
  //                   << ", newTotNumPacketsReceived: " << newTotNumPacketsReceived << "\n";

  if (newTotNumPacketsReceived == fTotNumPacketsReceived) {
    // No additional packets have been received since the last time we
    // checked, so end this stream:
    // *env << "Closing session, because we stopped receiving packets.\n";
    if (fVerbosityLevel > 0) {
      envir() << *this << "::doLivenessCheck last packet received: >" << fInterPacketGapMaxTime 
                       << " seconds ago. Resetting session\n";
    }
    continueAfterLivenessCommand(1/*hack*/, fServerSupportsGetParameter);
  } else {
    fTotNumPacketsReceived = newTotNumPacketsReceived;
    // Check again, after the specified delay:
    fInterPacketGapsTask = envir().taskScheduler().scheduleDelayedTask(fInterPacketGapMaxTime*MILLION, checkInterPacketGaps, this);
  }
}
示例#3
0
void checkForPacketArrival(void* /*clientData*/) {
    if (!notifyOnPacketArrival) return; // we're not checking
    
    // Check each subsession, to see whether it has received data packets:
    unsigned numSubsessionsChecked = 0;
    unsigned numSubsessionsWithReceivedData = 0;
    unsigned numSubsessionsThatHaveBeenSynced = 0;
    
    MediaSubsessionIterator iter(*session);
    MediaSubsession* subsession;
    while ((subsession = iter.next()) != NULL)
    {
        RTPSource* src = subsession->rtpSource();
        if (src == NULL) continue;
        ++numSubsessionsChecked;
        
        if (src->receptionStatsDB().numActiveSourcesSinceLastReset() > 0)
        {
            // At least one data packet has arrived
            ++numSubsessionsWithReceivedData;
        }
        if (src->hasBeenSynchronizedUsingRTCP())
            ++numSubsessionsThatHaveBeenSynced;
    }
    
    unsigned numSubsessionsToCheck = numSubsessionsChecked;
    // Special case for "QuickTimeFileSink"s and "AVIFileSink"s:
    // They might not use all of the input sources:
    if (qtOut != NULL)
        numSubsessionsToCheck = qtOut->numActiveSubsessions();
    
    else if (aviOut != NULL)
        numSubsessionsToCheck = aviOut->numActiveSubsessions();
    
    Boolean notifyTheUser;
    if (!syncStreams)
        notifyTheUser = numSubsessionsWithReceivedData > 0; // easy case
    else
    {
        notifyTheUser = numSubsessionsWithReceivedData >= numSubsessionsToCheck
        && numSubsessionsThatHaveBeenSynced == numSubsessionsChecked;
        // Note: A subsession with no active sources is considered to be synced
    }
    if (notifyTheUser)
    {
        struct timeval timeNow;
        gettimeofday(&timeNow, NULL);
        char timestampStr[100];
        sprintf(timestampStr, "%ld%03ld", timeNow.tv_sec, (long)(timeNow.tv_usec/1000));
        *env << (syncStreams ? "Synchronized d" : "D")
		<< "ata packets have begun arriving [" << timestampStr << "]\007\n";
        return;
    }
    
    // No luck, so reschedule this check again, after a delay:
    int uSecsToDelay = 100000; // 100 ms
    arrivalCheckTimerTask
    = env->taskScheduler().scheduleDelayedTask(uSecsToDelay,
                                               (TaskFunc*)checkForPacketArrival, NULL);
}
		void Live555ClientEngine::onStop()
		{
			if (session != nullptr)
			{
				MediaSubsession* subSession = nullptr;
				bool someSubsessionsWereActive = false;
				for (MediaSubsessionIterator iterator(*session); subSession != nullptr; subSession = iterator.next())
				{
					if (subSession->sink != nullptr)
					{
						Medium::close(subSession->sink);
						subSession->sink = nullptr;

						if (subSession->rtcpInstance() != nullptr)
						{
							// in case the server sends a RTCP "BYE" while handling "TEARDOWN"
							subSession->rtcpInstance()->setByeHandler(nullptr, nullptr);
						}

						someSubsessionsWereActive = true;
					}
				}

				if (someSubsessionsWereActive)
				{
					rtspClient->sendTeardownCommand(*session, nullptr);
				}
			}

			Medium::close(rtspClient);
			Medium::close(session);
		}
示例#5
0
Boolean MediaSession
::initiateByMediaType(char const* mimeType,
		      MediaSubsession*& resultSubsession,
		      int useSpecialRTPoffset) {
  // Look through this session's subsessions for media that match "mimeType"
  resultSubsession = NULL;
  MediaSubsessionIterator iter(*this);
  MediaSubsession* subsession;
  while ((subsession = iter.next()) != NULL) {
    Boolean wasAlreadyInitiated = subsession->readSource() != NULL;
    if (!wasAlreadyInitiated) {
      // Try to create a source for this subsession:
      if (!subsession->initiate(useSpecialRTPoffset)) return False;
    }

    // Make sure the source's MIME type is one that we handle:
    if (strcmp(subsession->readSource()->MIMEtype(), mimeType) != 0) {
      if (!wasAlreadyInitiated) subsession->deInitiate();
      continue;
    }

    resultSubsession = subsession;
    break; // use this
  }

  if (resultSubsession == NULL) {
    envir().setResultMsg("Session has no usable media subsession");
    return False;
  }

  return True;
}
示例#6
0
void beginQOSMeasurement() {
	// Set up a measurement record for each active subsession:
	struct timeval startTime;
	gettimeofday(&startTime, NULL);
	nextQOSMeasurementUSecs = startTime.tv_sec*1000000 + startTime.tv_usec;
	qosMeasurementRecord* qosRecordTail = NULL;
	MediaSubsessionIterator iter(*session);
	MediaSubsession* subsession;
	while ((subsession = iter.next()) != NULL) {
		RTPSource* src = subsession->rtpSource();
#ifdef SUPPORT_REAL_RTSP
		if (session->isRealNetworksRDT) src = (RTPSource*)(subsession->readSource()); // hack
#endif
		if (src == NULL) continue;

		qosMeasurementRecord* qosRecord
			= new qosMeasurementRecord(startTime, src);
		if (qosRecordHead == NULL) qosRecordHead = qosRecord;
		if (qosRecordTail != NULL) qosRecordTail->fNext = qosRecord;
		qosRecordTail  = qosRecord;
	}

	// Then schedule the first of the periodic measurements:
	scheduleNextQOSMeasurement();
}
示例#7
0
int CAimer39RTSPClient::GetStreamType( unsigned int nStreamNum, STREAM_TYPE & Type )
{
	StreamClientState& scs = m_pRTSPClient->scs; // alias
	MediaSubsessionIterator iter(*scs.session);
	MediaSubsession* subsession = NULL;
	int iStreamCnt = 0;

	iter.reset();

	while ( ( subsession = iter.next() ) != NULL ) {
		if ( strcmp( subsession->mediumName(), "video" ) == 0 ||
			 strcmp( subsession->mediumName(), "VIDEO" ) == 0 ) {
			Type = STREAM_VIDEO;
		} else if ( strcmp( subsession->mediumName(), "audio" ) == 0 ||
					strcmp( subsession->mediumName(), "AUDIO" ) == 0 ) {
			Type = STREAM_AUDIO;
		} else {
			Type = STREAM_UNKNOWN;
		}

		if (nStreamNum == iStreamCnt) break;

		++iStreamCnt;
	}

	iter.reset();
	
	return 0;
}
示例#8
0
AVIFileSink::~AVIFileSink() {
  completeOutputFile();

  // Then, stop streaming and delete each active "AVISubsessionIOState":
  MediaSubsessionIterator iter(fInputSession);
  MediaSubsession* subsession;
  while ((subsession = iter.next()) != NULL) {
    if (subsession->readSource() != NULL) subsession->readSource()->stopGettingFrames();

    AVISubsessionIOState* ioState
      = (AVISubsessionIOState*)(subsession->miscPtr);
    if (ioState == NULL) continue;

    delete ioState;
  }

  // Then, delete the index records:
  AVIIndexRecord* cur = fIndexRecordsHead;
  while (cur != NULL) {
    AVIIndexRecord* next = cur->next();
    delete cur;
    cur = next;
  }

  // Finally, close our output file:
  CloseOutputFile(fOutFid);
}
示例#9
0
void checkInterPacketGaps(void* /*clientData*/) {
  if (interPacketGapMaxTime == 0) return; // we're not checking

  // Check each subsession, counting up how many packets have been received:
  unsigned newTotNumPacketsReceived = 0;

  MediaSubsessionIterator iter(*session);
  MediaSubsession* subsession;
  while ((subsession = iter.next()) != NULL) {
    RTPSource* src = subsession->rtpSource();
    if (src == NULL) continue;
    newTotNumPacketsReceived += src->receptionStatsDB().totNumPacketsReceived();
  }

  if (newTotNumPacketsReceived == totNumPacketsReceived) {
    // No additional packets have been received since the last time we
    // checked, so end this stream:
    *env << "Closing session, because we stopped receiving packets.\n";
    interPacketGapCheckTimerTask = NULL;
    sessionAfterPlaying();
  } else {
    totNumPacketsReceived = newTotNumPacketsReceived;
    // Check again, after the specified delay:
    interPacketGapCheckTimerTask
      = env->taskScheduler().scheduleDelayedTask(interPacketGapMaxTime*1000000,
				 (TaskFunc*)checkInterPacketGaps, NULL);
  }
}
示例#10
0
void shutdownStream(RTSPClient* rtspClient, int exitCode)
 {
	ourRTSPClient* rtsp = (ourRTSPClient*)rtspClient;
	if (exitCode != 0)
	{
		//eventLoopWatchVariable = 1;
		//int nID = rtsp->m_nID;
		IPNC_CloseStream(rtsp->m_nID);
		return;
	}

  UsageEnvironment& env = rtspClient->envir(); // alias
  StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias

  // First, check whether any subsessions have still to be closed:
  if (scs.session != NULL) { 
    Boolean someSubsessionsWereActive = False;
    MediaSubsessionIterator iter(*scs.session);
    MediaSubsession* subsession;

    while ((subsession = iter.next()) != NULL) {
      if (subsession->sink != NULL) {
	Medium::close(subsession->sink);
	subsession->sink = NULL;

	if (subsession->rtcpInstance() != NULL) {
	  subsession->rtcpInstance()->setByeHandler(NULL, NULL); // in case the server sends a RTCP "BYE" while handling "TEARDOWN"
	}

	someSubsessionsWereActive = True;
      }
    }

    if (someSubsessionsWereActive) {
      // Send a RTSP "TEARDOWN" command, to tell the server to shutdown the stream.
      // Don't bother handling the response to the "TEARDOWN".
      rtspClient->sendTeardownCommand(*scs.session, NULL);
    }
  }

  env << *rtspClient << "Closing the stream.\n";
  Medium::close(rtspClient);

  
  rtsp = NULL;

  rtspClient = NULL;
    // Note that this will also cause this stream's "StreamClientState" structure to get reclaimed.

  //if (--rtspClientCount == 0)
  {
    // The final stream has ended, so exit the application now.
    // (Of course, if you're embedding this code into your own application, you might want to comment this out,
    // and replace it with "eventLoopWatchVariable = 1;", so that we leave the LIVE555 event loop, and continue running "main()".)
    //exit(exitCode);
	 //eventLoopWatchVariable = 1;
	//CXAgent::Instance().do_exit();
  }
}
ProxyServerMediaSubsession
::ProxyServerMediaSubsession(MediaSubsession& mediaSubsession,
			     portNumBits initialPortNum, Boolean multiplexRTCPWithRTP)
  : OnDemandServerMediaSubsession(mediaSubsession.parentSession().envir(), True/*reuseFirstSource*/,
				  initialPortNum, multiplexRTCPWithRTP),
    fClientMediaSubsession(mediaSubsession), fCodecName(strDup(mediaSubsession.codecName())),
    fNext(NULL), fHaveSetupStream(False) {
}
示例#12
0
int CAimer39RTSPClient::GetVideoFPS( unsigned int nStreamNum )
{
	MediaSubsession * subsession = findSubSessionByStreamNum( nStreamNum );

	if ( NULL == subsession ) return -1;

	IS_VIDEO_SUBS_R( subsession, -1 );

	return (int)subsession->videoFPS();
}
示例#13
0
char* MediaSession::absEndTime() const {
  if (fAbsEndTime != NULL) return fAbsEndTime;

  // If a subsession has an 'absolute' end time, then use that:
  MediaSubsessionIterator iter(*this);
  MediaSubsession* subsession;
  while ((subsession = iter.next()) != NULL) {
    if (subsession->_absEndTime() != NULL) return subsession->_absEndTime();
  }
  return NULL;
}
示例#14
0
void subsessionByeHandler(void* clientData) {
  struct timeval timeNow;
  gettimeofday(&timeNow, NULL);
  unsigned secsDiff = timeNow.tv_sec - startTime.tv_sec;

  MediaSubsession* subsession = (MediaSubsession*)clientData;
  *env << "Received RTCP \"BYE\" on \"" << subsession->mediumName()
	<< "/" << subsession->codecName()
	<< "\" subsession (after " << secsDiff
	<< " seconds)\n";

  // Act now as if the subsession had closed:
  subsessionAfterPlaying(subsession);
}
示例#15
0
AVIFileSink::AVIFileSink(UsageEnvironment& env,
			 MediaSession& inputSession,
			 char const* outputFileName,
			 unsigned bufferSize,
			 unsigned short movieWidth, unsigned short movieHeight,
			 unsigned movieFPS, Boolean packetLossCompensate)
  : Medium(env), fInputSession(inputSession),
    fIndexRecordsHead(NULL), fIndexRecordsTail(NULL), fNumIndexRecords(0),
    fBufferSize(bufferSize), fPacketLossCompensate(packetLossCompensate),
    fAreCurrentlyBeingPlayed(False), fNumSubsessions(0), fNumBytesWritten(0),
    fHaveCompletedOutputFile(False),
    fMovieWidth(movieWidth), fMovieHeight(movieHeight), fMovieFPS(movieFPS) {
  fOutFid = OpenOutputFile(env, outputFileName);
  if (fOutFid == NULL) return;

  // Set up I/O state for each input subsession:
  MediaSubsessionIterator iter(fInputSession);
  MediaSubsession* subsession;
  while ((subsession = iter.next()) != NULL) {
    // Ignore subsessions without a data source:
    FramedSource* subsessionSource = subsession->readSource();
    if (subsessionSource == NULL) continue;

    // If "subsession's" SDP description specified screen dimension
    // or frame rate parameters, then use these.
    if (subsession->videoWidth() != 0) {
      fMovieWidth = subsession->videoWidth();
    }
    if (subsession->videoHeight() != 0) {
      fMovieHeight = subsession->videoHeight();
    }
    if (subsession->videoFPS() != 0) {
      fMovieFPS = subsession->videoFPS();
    }

    AVISubsessionIOState* ioState
      = new AVISubsessionIOState(*this, *subsession);
    subsession->miscPtr = (void*)ioState;

    // Also set a 'BYE' handler for this subsession's RTCP instance:
    if (subsession->rtcpInstance() != NULL) {
      subsession->rtcpInstance()->setByeHandler(onRTCPBye, ioState);
    }

    ++fNumSubsessions;
  }

  // Begin by writing an AVI header:
  addFileHeader_AVI();
}
示例#16
0
BOOL setupStreams( unsigned *pResponseCode /*= NULL*/ ) 
{
	MediaSubsessionIterator iter(*session);
	MediaSubsession *subsession;
	Boolean madeProgress = False;

	BOOL bResult = TRUE;
	while ((subsession = iter.next()) != NULL) 
	{
		if (subsession->clientPortNum() == 0) continue; // port # was not set

		if ( !clientSetupSubsession(ourClient, subsession, streamUsingTCP, pResponseCode ) ) 
		{
			*env << "Failed to setup \"" << subsession->mediumName()
				<< "/" << subsession->codecName()
				<< "\" subsession: " << env->getResultMsg() << "\n";
			
			bResult = FALSE;
		}
		else 
		{
			*env << "Setup \"" << subsession->mediumName()
				<< "/" << subsession->codecName()
				<< "\" subsession (client ports " << subsession->clientPortNum()
				<< "-" << subsession->clientPortNum()+1 << ")\n";
			madeProgress = True;

			bResult = TRUE;
		}
	}
	//if (!madeProgress) 
	//	return bResult;
	return bResult;
}
示例#17
0
DefaultSink::DefaultSink(UsageEnvironment & env,
                         MediaSubsession & subsession,
                         char const * sink_url,
                         char const * stream_id)
        : MediaSink(env),
          _subsession(subsession),
          _receive_buffer(RECEIVE_BUFFER_SIZE),
          _stream_id(stream_id),
          _writer(libc2rtsp::sink::SinkFactory().gen(sink_url)),
          _verbose(true),
          _sprop_parameter_sets(),
          _have_written_first_frame(false)
{
    if (::strcmp(subsession.codecName(), "H264") == 0) {
        // For H.264 video stream, we use a special sink that adds 'start codes',
        // and (at the start) the SPS and PPS NAL units:
        _sprop_parameter_sets.emplace_back(std::string(subsession.fmtp_spropparametersets()));

    } else if (::strcmp(subsession.codecName(), "H265") == 0) {
        // For H.265 video stream, we use a special sink that adds 'start codes',
        // and (at the start) the VPS, SPS, and PPS NAL units:
        _sprop_parameter_sets.emplace_back(std::string(subsession.fmtp_spropvps())); // VPS
        _sprop_parameter_sets.emplace_back(std::string(subsession.fmtp_spropsps())); // SPS
        _sprop_parameter_sets.emplace_back(std::string(subsession.fmtp_sproppps())); // PPS

    } else {
        crLogE("DefaultSink::DefaultSink() Unsupported subsession: {}/{}",
               subsession.mediumName(), subsession.codecName());
        throw std::bad_alloc();
    }
}
示例#18
0
void subsessionAfterPlaying(void* clientData) {
  // Begin by closing this media subsession's stream:
  MediaSubsession* subsession = (MediaSubsession*)clientData;
  Medium::close(subsession->sink);
  subsession->sink = NULL;

  // Next, check whether *all* subsessions' streams have now been closed:
  MediaSession& session = subsession->parentSession();
  MediaSubsessionIterator iter(session);
  while ((subsession = iter.next()) != NULL) {
    if (subsession->sink != NULL) return; // this subsession is still active
  }

  // All subsessions' streams have now been closed
  sessionAfterPlaying();
}
void subsessionAfterPlaying(void* clientData) {
  MediaSubsession* subsession = (MediaSubsession*)clientData;
  RTSPClient* rtspClient = (RTSPClient*)(subsession->miscPtr);

  // Begin by closing this subsession's stream:
  Medium::close(subsession->sink);
  subsession->sink = NULL;

  // Next, check whether *all* subsessions' streams have now been closed:
  MediaSession& session = subsession->parentSession();
  MediaSubsessionIterator iter(session);
  while ((subsession = iter.next()) != NULL) {
    if (subsession->sink != NULL) return; // this subsession is still active
  }

  // All subsessions' streams have now been closed, so shutdown the client:
  shutdownStream(rtspClient, 1);
}
bool MtkRTSPClient::IsPacketArrived()
{
    MediaSubsessionIterator iter(*session);
    MediaSubsession* subsession;
    while ((subsession = iter.next()) != NULL) 
    {
        RTPSource* src = subsession->rtpSource();
        if (src == NULL) 
            continue;

        if (src->receptionStatsDB().numActiveSourcesSinceLastReset() > 0) 
        {
            return true;
        }
    }

    return false;
}
示例#21
0
void CAimer39RTSPClient::shutdownStream( RTSPClient* rtspClient ) 
{
	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";
		return;
	}

	// First, check whether any subsessions have still to be closed:
	if (scs.session != NULL) { 
		Boolean someSubsessionsWereActive = False;
		MediaSubsessionIterator iter(*scs.session);
		MediaSubsession* subsession;

		while ((subsession = iter.next()) != NULL) {
			if (subsession->sink != NULL) {
				Medium::close(subsession->sink);
				subsession->sink = NULL;

				if (subsession->rtcpInstance() != NULL) {
					subsession->rtcpInstance()->setByeHandler(NULL, NULL); // in case the server sends a RTCP "BYE" while handling "TEARDOWN"
				}

				someSubsessionsWereActive = True;
			}
		}

		if (someSubsessionsWereActive) {
			// Send a RTSP "TEARDOWN" command, to tell the server to shutdown the stream.
			// Don't bother handling the response to the "TEARDOWN".
			rtspClient->sendTeardownCommand(*scs.session, NULL);
		}
	}

	env << *rtspClient << "Closing the stream.\n";
	arc->m_bIsShutDown = true;
	if (arc->m_pFinishCallback)	arc->m_pFinishCallback(arc->m_pCallBackParam, arc); //call back inform stream over
	Medium::close(rtspClient);
	// Note that this will also cause this stream's "StreamClientState" structure to get reclaimed.
}
void ProxyServerMediaSession::continueAfterDESCRIBE(char const* sdpDescription) {
    describeCompletedFlag = 1;

    // Create a (client) "MediaSession" object from the stream's SDP description ("resultString"), then iterate through its
    // "MediaSubsession" objects, to set up corresponding "ServerMediaSubsession" objects that we'll use to serve the stream's tracks.
    do {
        fClientMediaSession = MediaSession::createNew(envir(), sdpDescription);
        if (fClientMediaSession == NULL) break;

        MediaSubsessionIterator iter(*fClientMediaSession);
        for (MediaSubsession* mss = iter.next(); mss != NULL; mss = iter.next()) {
            ServerMediaSubsession* smss = new ProxyServerMediaSubsession(*mss);
            addSubsession(smss);
            if (fVerbosityLevel > 0) {
                envir() << *this << " added new \"ProxyServerMediaSubsession\" for "
                        << mss->protocolName() << "/" << mss->mediumName() << "/" << mss->codecName() << " track\n";
            }
        }
    } while (0);
}
示例#23
0
bool CRTSPClient::setupStreams()
{
  //setup streams
  XBMC->Log(LOG_DEBUG, "CRTSPClient::setupStreams()");
  Boolean madeProgress=False;
  MediaSubsessionIterator iter(*m_session);
  MediaSubsession *subsession;

  while ((subsession = iter.next()) != NULL) 
  {
    if (subsession->clientPortNum() == 0) continue; // port # was not set

    if (!clientSetupSubsession(m_ourClient, subsession, streamUsingTCP)) 
    {
      XBMC->Log(LOG_DEBUG,  "Failed to setup %s %s %s" ,subsession->mediumName(),subsession->codecName(),m_env->getResultMsg() );;
    } 
    else 
    {
      XBMC->Log(LOG_DEBUG,  "Setup %s %s %d %d" ,subsession->mediumName(),subsession->codecName(),subsession->clientPortNum(),subsession->clientPortNum()+1);;
      madeProgress = True;
    }
  }
  if (!madeProgress) 
  {
    shutdown();
    return false;
  }
  return true;
}
示例#24
0
void beginQOSMeasurement(MediaSession *session, TaskToken qosMeasurementTimerTask, unsigned int qosMeasurementIntervalMS, UsageEnvironment *env) {
    // Set up a measurement record for each active subsession:
    struct timeval startTime;
    gettimeofday(&startTime, NULL);
    nextQOSMeasurementUSecs = startTime.tv_sec*1000000 + startTime.tv_usec;
    qosMeasurementRecord* qosRecordTail = NULL;
    MediaSubsessionIterator iter(*session);
    MediaSubsession* subsession;
    while ((subsession = iter.next()) != NULL) {
        RTPSource* src = subsession->rtpSource();
        if (src == NULL) continue;
        
        qosMeasurementRecord* qosRecord
        = new qosMeasurementRecord(startTime, src);
        if (qosRecordHead == NULL) qosRecordHead = qosRecord;
        if (qosRecordTail != NULL) qosRecordTail->fNext = qosRecord;
        qosRecordTail  = qosRecord;
    }
    
    // Then schedule the first of the periodic measurements:
    scheduleNextQOSMeasurement(qosMeasurementTimerTask, qosMeasurementIntervalMS, env);
}
示例#25
0
AVISubsessionIOState::AVISubsessionIOState(AVIFileSink& sink,
				     MediaSubsession& subsession)
  : fOurSink(sink), fOurSubsession(subsession),
    fMaxBytesPerSecond(0), fIsVideo(False), fIsAudio(False), fIsByteSwappedAudio(False), fNumFrames(0) {
  fBuffer = new SubsessionBuffer(fOurSink.fBufferSize);
  fPrevBuffer = sink.fPacketLossCompensate
    ? new SubsessionBuffer(fOurSink.fBufferSize) : NULL;

  FramedSource* subsessionSource = subsession.readSource();
  fOurSourceIsActive = subsessionSource != NULL;

  fPrevPresentationTime.tv_sec = 0;
  fPrevPresentationTime.tv_usec = 0;
}
示例#26
0
// Used to shut down and close a stream (including its "RTSPClient" object):
void StreamClient::shutdownStream()
{
    // First, check whether any subsessions have still to be closed:
    if (_state.session != nullptr) {
        Boolean someSubsessionsWereActive = False;
        MediaSubsessionIterator iter(*_state.session);
        MediaSubsession * subsession = nullptr;

        while ((subsession = iter.next()) != nullptr) {
            if (subsession->sink != nullptr) {
                Medium::close(subsession->sink);
                subsession->sink = nullptr;

                if (subsession->rtcpInstance() != nullptr) {
                    subsession->rtcpInstance()->setByeHandler(nullptr, nullptr); // in case the server sends a RTCP "BYE" while handling "TEARDOWN"
                }
                someSubsessionsWereActive = True;
            }
        }

        if (someSubsessionsWereActive) {
            sendTeardown(*_state.session);
        }
    }

    crLogN("StreamClient::shutdownStream() Closing the stream.");
    Medium::close(this);
    // Note that this will also cause this stream's "StreamClientState" structure to get reclaimed.

//    if (--rtspClientCount == 0) {
//        // The final stream has ended, so exit the application now.
//        // (Of course, if you're embedding this code into your own application, you might want to comment this out,
//        // and replace it with "eventLoopWatchVariable = 1;", so that we leave the LIVE555 event loop, and continue running "main()".)
//        exit(exitCode);
//    }
    exit(0);
}
示例#27
0
void setupStreams() {
  MediaSubsessionIterator iter(*session);
  MediaSubsession *subsession;
  Boolean madeProgress = False;

  while ((subsession = iter.next()) != NULL) {
    if (subsession->clientPortNum() == 0) continue; // port # was not set

    if (!clientSetupSubsession(ourClient, subsession, streamUsingTCP)) {
      *env << "Failed to setup \"" << subsession->mediumName()
		    << "/" << subsession->codecName()
		    << "\" subsession: " << env->getResultMsg() << "\n";
    } else {
      *env << "Setup \"" << subsession->mediumName()
		    << "/" << subsession->codecName()
		    << "\" subsession (client ports " << subsession->clientPortNum()
		    << "-" << subsession->clientPortNum()+1 << ")\n";
      madeProgress = True;
    }
  }
  if (!madeProgress) shutdown();
}
ProxyServerMediaSubsession::ProxyServerMediaSubsession(MediaSubsession& mediaSubsession)
    : OnDemandServerMediaSubsession(mediaSubsession.parentSession().envir(), True/*reuseFirstSource*/),
      fClientMediaSubsession(mediaSubsession), fNext(NULL), fHaveSetupStream(False) {
}
示例#29
0
void printQOSData(int exitCode) {
  *env << "begin_QOS_statistics\n";
  
  // Print out stats for each active subsession:
  qosMeasurementRecord* curQOSRecord = qosRecordHead;
  if (session != NULL) {
    MediaSubsessionIterator iter(*session);
    MediaSubsession* subsession;
    while ((subsession = iter.next()) != NULL) {
      RTPSource* src = subsession->rtpSource();
      if (src == NULL) continue;
      
      *env << "subsession\t" << subsession->mediumName()
	   << "/" << subsession->codecName() << "\n";
      
      unsigned numPacketsReceived = 0, numPacketsExpected = 0;
      
      if (curQOSRecord != NULL) {
	numPacketsReceived = curQOSRecord->totNumPacketsReceived;
	numPacketsExpected = curQOSRecord->totNumPacketsExpected;
      }
      *env << "num_packets_received\t" << numPacketsReceived << "\n";
      *env << "num_packets_lost\t" << int(numPacketsExpected - numPacketsReceived) << "\n";
      
      if (curQOSRecord != NULL) {
	unsigned secsDiff = curQOSRecord->measurementEndTime.tv_sec
	  - curQOSRecord->measurementStartTime.tv_sec;
	int usecsDiff = curQOSRecord->measurementEndTime.tv_usec
	  - curQOSRecord->measurementStartTime.tv_usec;
	double measurementTime = secsDiff + usecsDiff/1000000.0;
	*env << "elapsed_measurement_time\t" << measurementTime << "\n";
	
	*env << "kBytes_received_total\t" << curQOSRecord->kBytesTotal << "\n";
	
	*env << "measurement_sampling_interval_ms\t" << qosMeasurementIntervalMS << "\n";
	
	if (curQOSRecord->kbits_per_second_max == 0) {
	  // special case: we didn't receive any data:
	  *env <<
	    "kbits_per_second_min\tunavailable\n"
	    "kbits_per_second_ave\tunavailable\n"
	    "kbits_per_second_max\tunavailable\n";
	} else {
	  *env << "kbits_per_second_min\t" << curQOSRecord->kbits_per_second_min << "\n";
	  *env << "kbits_per_second_ave\t"
	       << (measurementTime == 0.0 ? 0.0 : 8*curQOSRecord->kBytesTotal/measurementTime) << "\n";
	  *env << "kbits_per_second_max\t" << curQOSRecord->kbits_per_second_max << "\n";
	}
	
	*env << "packet_loss_percentage_min\t" << 100*curQOSRecord->packet_loss_fraction_min << "\n";
	double packetLossFraction = numPacketsExpected == 0 ? 1.0
	  : 1.0 - numPacketsReceived/(double)numPacketsExpected;
	if (packetLossFraction < 0.0) packetLossFraction = 0.0;
	*env << "packet_loss_percentage_ave\t" << 100*packetLossFraction << "\n";
	*env << "packet_loss_percentage_max\t"
	     << (packetLossFraction == 1.0 ? 100.0 : 100*curQOSRecord->packet_loss_fraction_max) << "\n";
	
	RTPReceptionStatsDB::Iterator statsIter(src->receptionStatsDB());
	// Assume that there's only one SSRC source (usually the case):
	RTPReceptionStats* stats = statsIter.next(True);
	if (stats != NULL) {
	  *env << "inter_packet_gap_ms_min\t" << stats->minInterPacketGapUS()/1000.0 << "\n";
	  struct timeval totalGaps = stats->totalInterPacketGaps();
	  double totalGapsMS = totalGaps.tv_sec*1000.0 + totalGaps.tv_usec/1000.0;
	  unsigned totNumPacketsReceived = stats->totNumPacketsReceived();
	  *env << "inter_packet_gap_ms_ave\t"
	       << (totNumPacketsReceived == 0 ? 0.0 : totalGapsMS/totNumPacketsReceived) << "\n";
	  *env << "inter_packet_gap_ms_max\t" << stats->maxInterPacketGapUS()/1000.0 << "\n";
	}
	
	curQOSRecord = curQOSRecord->fNext;
      }
    }
  }

  *env << "end_QOS_statistics\n";
  delete qosRecordHead;
}
示例#30
0
void continueAfterDESCRIBE(RTSPClient*, int resultCode, char* resultString) {
  if (resultCode != 0) {
    *env << "Failed to get a SDP description from URL \"" << streamURL << "\": " << resultString << "\n";
    shutdown();
  }

  char* sdpDescription = resultString;
  *env << "Opened URL \"" << streamURL << "\", returning a SDP description:\n" << sdpDescription << "\n";

  // Create a media session object from this SDP description:
  session = MediaSession::createNew(*env, sdpDescription);
  delete[] sdpDescription;
  if (session == NULL) {
    *env << "Failed to create a MediaSession object from the SDP description: " << env->getResultMsg() << "\n";
    shutdown();
  } else if (!session->hasSubsessions()) {
    *env << "This session has no media subsessions (i.e., \"m=\" lines)\n";
    shutdown();
  }

  // Then, setup the "RTPSource"s for the session:
  MediaSubsessionIterator iter(*session);
  MediaSubsession *subsession;
  Boolean madeProgress = False;
  char const* singleMediumToTest = singleMedium;
  while ((subsession = iter.next()) != NULL) {
    // If we've asked to receive only a single medium, then check this now:
    if (singleMediumToTest != NULL) {
      if (strcmp(subsession->mediumName(), singleMediumToTest) != 0) {
		  *env << "Ignoring \"" << subsession->mediumName()
			  << "/" << subsession->codecName()
			  << "\" subsession, because we've asked to receive a single " << singleMedium
			  << " session only\n";
	continue;
      } else {
	// Receive this subsession only
	singleMediumToTest = "xxxxx";
	    // this hack ensures that we get only 1 subsession of this type
      }
    }

    if (desiredPortNum != 0) {
      subsession->setClientPortNum(desiredPortNum);
      desiredPortNum += 2;
    }

    if (createReceivers) {
      if (!subsession->initiate(simpleRTPoffsetArg)) {
	*env << "Unable to create receiver for \"" << subsession->mediumName()
	     << "/" << subsession->codecName()
	     << "\" subsession: " << env->getResultMsg() << "\n";
      } else {
	*env << "Created receiver for \"" << subsession->mediumName()
	     << "/" << subsession->codecName()
	     << "\" subsession (client ports " << subsession->clientPortNum()
	     << "-" << subsession->clientPortNum()+1 << ")\n";
	madeProgress = True;
	
	if (subsession->rtpSource() != NULL) {
	  // Because we're saving the incoming data, rather than playing
	  // it in real time, allow an especially large time threshold
	  // (1 second) for reordering misordered incoming packets:
	  unsigned const thresh = 1000000; // 1 second
	  subsession->rtpSource()->setPacketReorderingThresholdTime(thresh);
	  
	  // Set the RTP source's OS socket buffer size as appropriate - either if we were explicitly asked (using -B),
	  // or if the desired FileSink buffer size happens to be larger than the current OS socket buffer size.
	  // (The latter case is a heuristic, on the assumption that if the user asked for a large FileSink buffer size,
	  // then the input data rate may be large enough to justify increasing the OS socket buffer size also.)
	  int socketNum = subsession->rtpSource()->RTPgs()->socketNum();
	  unsigned curBufferSize = getReceiveBufferSize(*env, socketNum);
	  if (socketInputBufferSize > 0 || fileSinkBufferSize > curBufferSize) {
	    unsigned newBufferSize = socketInputBufferSize > 0 ? socketInputBufferSize : fileSinkBufferSize;
	    newBufferSize = setReceiveBufferTo(*env, socketNum, newBufferSize);
	    if (socketInputBufferSize > 0) { // The user explicitly asked for the new socket buffer size; announce it:
	      *env << "Changed socket receive buffer size for the \""
		   << subsession->mediumName()
		   << "/" << subsession->codecName()
		   << "\" subsession from "
		   << curBufferSize << " to "
		   << newBufferSize << " bytes\n";
	    }
	  }
	}
      }
    } else {
      if (subsession->clientPortNum() == 0) {
	*env << "No client port was specified for the \""
	     << subsession->mediumName()
	     << "/" << subsession->codecName()
	     << "\" subsession.  (Try adding the \"-p <portNum>\" option.)\n";
      } else {
		madeProgress = True;
      }
    }
  }
  if (!madeProgress) shutdown();

  // Perform additional 'setup' on each subsession, before playing them:
  setupStreams();
}