#include "playCommon.hh"#include "BasicUsageEnvironment.hh"#include "GroupsockHelper.hh"#include <signal.h>Include dependency graph for playCommon.cpp:

Go to the source code of this file.
| #define USE_SIGNALS 1 |
Definition at line 31 of file playCommon.cpp.
| void beginQOSMeasurement | ( | ) |
Definition at line 1064 of file playCommon.cpp.
References qosMeasurementRecord::fNext, iter, MediaSubsessionIterator::next(), nextQOSMeasurementUSecs, NULL, qosRecordHead, MediaSubsession::readSource(), MediaSubsession::rtpSource(), scheduleNextQOSMeasurement(), session, and subsession.
Referenced by startPlayingStreams().
01064 { 01065 // Set up a measurement record for each active subsession: 01066 struct timeval startTime; 01067 gettimeofday(&startTime, NULL); 01068 nextQOSMeasurementUSecs = startTime.tv_sec*1000000 + startTime.tv_usec; 01069 qosMeasurementRecord* qosRecordTail = NULL; 01070 MediaSubsessionIterator iter(*session); 01071 MediaSubsession* subsession; 01072 while ((subsession = iter.next()) != NULL) { 01073 RTPSource* src = subsession->rtpSource(); 01074 #ifdef SUPPORT_REAL_RTSP 01075 if (session->isRealNetworksRDT) src = (RTPSource*)(subsession->readSource()); // hack 01076 #endif 01077 if (src == NULL) continue; 01078 01079 qosMeasurementRecord* qosRecord 01080 = new qosMeasurementRecord(startTime, src); 01081 if (qosRecordHead == NULL) qosRecordHead = qosRecord; 01082 if (qosRecordTail != NULL) qosRecordTail->fNext = qosRecord; 01083 qosRecordTail = qosRecord; 01084 } 01085 01086 // Then schedule the first of the periodic measurements: 01087 scheduleNextQOSMeasurement(); 01088 }
| void checkForPacketArrival | ( | void * | clientData | ) |
Definition at line 1221 of file playCommon.cpp.
References arrivalCheckTimerTask, aviOut, env, RTPSource::hasBeenSynchronizedUsingRTCP(), iter, MediaSubsessionIterator::next(), notifyOnPacketArrival, NULL, RTPReceptionStatsDB::numActiveSourcesSinceLastReset(), AVIFileSink::numActiveSubsessions(), QuickTimeFileSink::numActiveSubsessions(), qtOut, RTPSource::receptionStatsDB(), MediaSubsession::rtpSource(), TaskScheduler::scheduleDelayedTask(), session, subsession, syncStreams, and UsageEnvironment::taskScheduler().
Referenced by startPlayingStreams().
01221 { 01222 if (!notifyOnPacketArrival) return; // we're not checking 01223 01224 // Check each subsession, to see whether it has received data packets: 01225 unsigned numSubsessionsChecked = 0; 01226 unsigned numSubsessionsWithReceivedData = 0; 01227 unsigned numSubsessionsThatHaveBeenSynced = 0; 01228 01229 MediaSubsessionIterator iter(*session); 01230 MediaSubsession* subsession; 01231 while ((subsession = iter.next()) != NULL) { 01232 RTPSource* src = subsession->rtpSource(); 01233 if (src == NULL) continue; 01234 ++numSubsessionsChecked; 01235 01236 if (src->receptionStatsDB().numActiveSourcesSinceLastReset() > 0) { 01237 // At least one data packet has arrived 01238 ++numSubsessionsWithReceivedData; 01239 } 01240 if (src->hasBeenSynchronizedUsingRTCP()) { 01241 ++numSubsessionsThatHaveBeenSynced; 01242 } 01243 } 01244 01245 unsigned numSubsessionsToCheck = numSubsessionsChecked; 01246 // Special case for "QuickTimeFileSink"s and "AVIFileSink"s: 01247 // They might not use all of the input sources: 01248 if (qtOut != NULL) { 01249 numSubsessionsToCheck = qtOut->numActiveSubsessions(); 01250 } else if (aviOut != NULL) { 01251 numSubsessionsToCheck = aviOut->numActiveSubsessions(); 01252 } 01253 01254 Boolean notifyTheUser; 01255 if (!syncStreams) { 01256 notifyTheUser = numSubsessionsWithReceivedData > 0; // easy case 01257 } else { 01258 notifyTheUser = numSubsessionsWithReceivedData >= numSubsessionsToCheck 01259 && numSubsessionsThatHaveBeenSynced == numSubsessionsChecked; 01260 // Note: A subsession with no active sources is considered to be synced 01261 } 01262 if (notifyTheUser) { 01263 struct timeval timeNow; 01264 gettimeofday(&timeNow, NULL); 01265 char timestampStr[100]; 01266 sprintf(timestampStr, "%ld%03ld", timeNow.tv_sec, timeNow.tv_usec/1000); 01267 *env << (syncStreams ? "Synchronized d" : "D") 01268 << "ata packets have begun arriving [" << timestampStr << "]\007\n"; 01269 return; 01270 } 01271 01272 // No luck, so reschedule this check again, after a delay: 01273 int uSecsToDelay = 100000; // 100 ms 01274 arrivalCheckTimerTask 01275 = env->taskScheduler().scheduleDelayedTask(uSecsToDelay, 01276 (TaskFunc*)checkForPacketArrival, NULL); 01277 }
| void checkInterPacketGaps | ( | void * | clientData | ) |
Definition at line 1279 of file playCommon.cpp.
References env, interPacketGapCheckTimerTask, interPacketGapMaxTime, iter, MediaSubsessionIterator::next(), NULL, RTPSource::receptionStatsDB(), MediaSubsession::rtpSource(), TaskScheduler::scheduleDelayedTask(), session, sessionAfterPlaying(), subsession, UsageEnvironment::taskScheduler(), totNumPacketsReceived, and RTPReceptionStatsDB::totNumPacketsReceived().
Referenced by startPlayingStreams().
01279 { 01280 if (interPacketGapMaxTime == 0) return; // we're not checking 01281 01282 // Check each subsession, counting up how many packets have been received: 01283 unsigned newTotNumPacketsReceived = 0; 01284 01285 MediaSubsessionIterator iter(*session); 01286 MediaSubsession* subsession; 01287 while ((subsession = iter.next()) != NULL) { 01288 RTPSource* src = subsession->rtpSource(); 01289 if (src == NULL) continue; 01290 newTotNumPacketsReceived += src->receptionStatsDB().totNumPacketsReceived(); 01291 } 01292 01293 if (newTotNumPacketsReceived == totNumPacketsReceived) { 01294 // No additional packets have been received since the last time we 01295 // checked, so end this stream: 01296 *env << "Closing session, because we stopped receiving packets.\n"; 01297 interPacketGapCheckTimerTask = NULL; 01298 sessionAfterPlaying(); 01299 } else { 01300 totNumPacketsReceived = newTotNumPacketsReceived; 01301 // Check again, after the specified delay: 01302 interPacketGapCheckTimerTask 01303 = env->taskScheduler().scheduleDelayedTask(interPacketGapMaxTime*1000000, 01304 (TaskFunc*)checkInterPacketGaps, NULL); 01305 } 01306 }
| void closeMediaSinks | ( | ) |
Definition at line 872 of file playCommon.cpp.
References aviOut, Medium::close(), iter, MediaSubsessionIterator::next(), NULL, qtOut, session, MediaSubsession::sink, and subsession.
Referenced by shutdown().
00872 { 00873 Medium::close(qtOut); 00874 Medium::close(aviOut); 00875 00876 if (session == NULL) return; 00877 MediaSubsessionIterator iter(*session); 00878 MediaSubsession* subsession; 00879 while ((subsession = iter.next()) != NULL) { 00880 Medium::close(subsession->sink); 00881 subsession->sink = NULL; 00882 } 00883 }
| int main | ( | int | argc, | |
| char ** | argv | |||
| ) |
Definition at line 117 of file playCommon.cpp.
References FileSink::addData(), allowProxyServers, audioOnly, aviOut, MediaSubsession::clientPortNum(), clientProtocolName, MediaSubsession::codecName(), controlConnectionUsesTCP, createClient(), H264VideoFileSink::createNew(), AMRAudioFileSink::createNew(), FileSink::createNew(), AVIFileSink::createNew(), QuickTimeFileSink::createNew(), MediaSession::createNew(), BasicUsageEnvironment::createNew(), BasicTaskScheduler::createNew(), createReceivers, NetAddress::data(), desiredAudioRTPPayloadFormat, TaskScheduler::doEventLoop(), duration, durationSlop, env, False, fileNamePrefix, fileSinkBufferSize, NetAddressList::firstAddress(), MediaSubsession::fmtp_config(), generateHintTracks, generateMP4Format, getOptionsResponse(), getReceiveBufferSize(), UsageEnvironment::getResultMsg(), getSDPDescriptionFromURL(), MediaSession::hasSubsessions(), initialSeekTime, MediaSubsession::initiate(), interPacketGapMaxTime, iter, MediaSubsession::mediumName(), mimeSubtype, movieFPS, movieFPSOptionSet, movieHeight, movieHeightOptionSet, movieWidth, movieWidthOptionSet, MediaSubsessionIterator::next(), notifyOnPacketArrival, NULL, NetAddressList::numAddresses(), oneFilePerFrame, ourClient, outputAVIFile, outputQuickTimeFile, packetLossCompensate, parseGeneralConfigStr(), password, playContinuously, progName, proxyServerName, proxyServerPortNum, qosMeasurementIntervalMS, qtOut, MediaSubsession::readSource(), ReceivingInterfaceAddr, MediaSubsessionIterator::reset(), MediaSubsession::rtcpInstance(), RTPSource::RTPgs(), MediaSubsession::rtpSource(), scale, sendOptionsRequest, sendOptionsRequestOnly, session, sessionAfterPlaying(), RTCPInstance::setByeHandler(), MediaSubsession::setClientPortNum(), RTPSource::setPacketReorderingThresholdTime(), setReceiveBufferTo(), setupStreams(), shutdown(), signalHandlerShutdown(), simpleRTPoffsetArg, singleMedium, MediaSubsession::sink, socketInputBufferSize, Socket::socketNum(), MediaSink::startPlaying(), AVIFileSink::startPlaying(), QuickTimeFileSink::startPlaying(), startPlayingStreams(), startTime, streamUsingTCP, subsession, subsessionAfterPlaying(), subsessionByeHandler(), syncStreams, UsageEnvironment::taskScheduler(), True, tunnelOverHTTPPortNum, usage(), username, verbosityLevel, and videoOnly.
00117 { 00118 // Begin by setting up our usage environment: 00119 TaskScheduler* scheduler = BasicTaskScheduler::createNew(); 00120 env = BasicUsageEnvironment::createNew(*scheduler); 00121 00122 progName = argv[0]; 00123 00124 gettimeofday(&startTime, NULL); 00125 00126 #ifdef USE_SIGNALS 00127 // Allow ourselves to be shut down gracefully by a SIGHUP or a SIGUSR1: 00128 signal(SIGHUP, signalHandlerShutdown); 00129 signal(SIGUSR1, signalHandlerShutdown); 00130 #endif 00131 00132 unsigned short desiredPortNum = 0; 00133 00134 // unfortunately we can't use getopt() here, as Windoze doesn't have it 00135 while (argc > 2) { 00136 char* const opt = argv[1]; 00137 if (opt[0] != '-') usage(); 00138 switch (opt[1]) { 00139 00140 case 'p': { // specify start port number 00141 int portArg; 00142 if (sscanf(argv[2], "%d", &portArg) != 1) { 00143 usage(); 00144 } 00145 if (portArg <= 0 || portArg >= 65536 || portArg&1) { 00146 *env << "bad port number: " << portArg 00147 << " (must be even, and in the range (0,65536))\n"; 00148 usage(); 00149 } 00150 desiredPortNum = (unsigned short)portArg; 00151 ++argv; --argc; 00152 break; 00153 } 00154 00155 case 'r': { // do not receive data (instead, just 'play' the stream(s)) 00156 createReceivers = False; 00157 break; 00158 } 00159 00160 case 'q': { // output a QuickTime file (to stdout) 00161 outputQuickTimeFile = True; 00162 break; 00163 } 00164 00165 case '4': { // output a 'mp4'-format file (to stdout) 00166 outputQuickTimeFile = True; 00167 generateMP4Format = True; 00168 break; 00169 } 00170 00171 case 'i': { // output an AVI file (to stdout) 00172 outputAVIFile = True; 00173 break; 00174 } 00175 00176 case 'I': { // specify input interface... 00177 NetAddressList addresses(argv[2]); 00178 if (addresses.numAddresses() == 0) { 00179 *env << "Failed to find network address for \"" << argv[2] << "\""; 00180 break; 00181 } 00182 ReceivingInterfaceAddr = *(unsigned*)(addresses.firstAddress()->data()); 00183 ++argv; --argc; 00184 break; 00185 } 00186 00187 case 'a': { // receive/record an audio stream only 00188 audioOnly = True; 00189 singleMedium = "audio"; 00190 break; 00191 } 00192 00193 case 'v': { // receive/record a video stream only 00194 videoOnly = True; 00195 singleMedium = "video"; 00196 break; 00197 } 00198 00199 case 'V': { // disable verbose output 00200 verbosityLevel = 0; 00201 break; 00202 } 00203 00204 case 'd': { // specify duration, or how much to delay after end time 00205 float arg; 00206 if (sscanf(argv[2], "%g", &arg) != 1) { 00207 usage(); 00208 } 00209 if (argv[2][0] == '-') { // not "arg<0", in case argv[2] was "-0" 00210 // a 'negative' argument was specified; use this for "durationSlop": 00211 duration = 0; // use whatever's in the SDP 00212 durationSlop = -arg; 00213 } else { 00214 duration = arg; 00215 durationSlop = 0; 00216 } 00217 ++argv; --argc; 00218 break; 00219 } 00220 00221 case 'D': { // specify maximum number of seconds to wait for packets: 00222 if (sscanf(argv[2], "%u", &interPacketGapMaxTime) != 1) { 00223 usage(); 00224 } 00225 ++argv; --argc; 00226 break; 00227 } 00228 00229 case 'c': { // play continuously 00230 playContinuously = True; 00231 break; 00232 } 00233 00234 case 'S': { // specify an offset to use with "SimpleRTPSource"s 00235 if (sscanf(argv[2], "%d", &simpleRTPoffsetArg) != 1) { 00236 usage(); 00237 } 00238 if (simpleRTPoffsetArg < 0) { 00239 *env << "offset argument to \"-S\" must be >= 0\n"; 00240 usage(); 00241 } 00242 ++argv; --argc; 00243 break; 00244 } 00245 00246 case 'O': { // Don't send an "OPTIONS" request before "DESCRIBE" 00247 sendOptionsRequest = False; 00248 break; 00249 } 00250 00251 case 'o': { // Send only the "OPTIONS" request to the server 00252 sendOptionsRequestOnly = True; 00253 break; 00254 } 00255 00256 case 'm': { // output multiple files - one for each frame 00257 oneFilePerFrame = True; 00258 break; 00259 } 00260 00261 case 'n': { // notify the user when the first data packet arrives 00262 notifyOnPacketArrival = True; 00263 break; 00264 } 00265 00266 case 't': { 00267 // stream RTP and RTCP over the TCP 'control' connection 00268 if (controlConnectionUsesTCP) { 00269 streamUsingTCP = True; 00270 } else { 00271 usage(); 00272 } 00273 break; 00274 } 00275 00276 case 'T': { 00277 // stream RTP and RTCP over a HTTP connection 00278 if (controlConnectionUsesTCP) { 00279 if (argc > 3 && argv[2][0] != '-') { 00280 // The next argument is the HTTP server port number: 00281 if (sscanf(argv[2], "%hu", &tunnelOverHTTPPortNum) == 1 00282 && tunnelOverHTTPPortNum > 0) { 00283 ++argv; --argc; 00284 break; 00285 } 00286 } 00287 } 00288 00289 // If we get here, the option was specified incorrectly: 00290 usage(); 00291 break; 00292 } 00293 00294 case 'u': { // specify a username and password 00295 username = argv[2]; 00296 password = argv[3]; 00297 argv+=2; argc-=2; 00298 if (allowProxyServers && argc > 3 && argv[2][0] != '-') { 00299 // The next argument is the name of a proxy server: 00300 proxyServerName = argv[2]; 00301 ++argv; --argc; 00302 00303 if (argc > 3 && argv[2][0] != '-') { 00304 // The next argument is the proxy server port number: 00305 if (sscanf(argv[2], "%hu", &proxyServerPortNum) != 1) { 00306 usage(); 00307 } 00308 ++argv; --argc; 00309 } 00310 } 00311 break; 00312 } 00313 00314 case 'A': { // specify a desired audio RTP payload format 00315 unsigned formatArg; 00316 if (sscanf(argv[2], "%u", &formatArg) != 1 00317 || formatArg >= 96) { 00318 usage(); 00319 } 00320 desiredAudioRTPPayloadFormat = (unsigned char)formatArg; 00321 ++argv; --argc; 00322 break; 00323 } 00324 00325 case 'M': { // specify a MIME subtype for a dynamic RTP payload type 00326 mimeSubtype = argv[2]; 00327 if (desiredAudioRTPPayloadFormat==0) desiredAudioRTPPayloadFormat =96; 00328 ++argv; --argc; 00329 break; 00330 } 00331 00332 case 'w': { // specify a width (pixels) for an output QuickTime or AVI movie 00333 if (sscanf(argv[2], "%hu", &movieWidth) != 1) { 00334 usage(); 00335 } 00336 movieWidthOptionSet = True; 00337 ++argv; --argc; 00338 break; 00339 } 00340 00341 case 'h': { // specify a height (pixels) for an output QuickTime or AVI movie 00342 if (sscanf(argv[2], "%hu", &movieHeight) != 1) { 00343 usage(); 00344 } 00345 movieHeightOptionSet = True; 00346 ++argv; --argc; 00347 break; 00348 } 00349 00350 case 'f': { // specify a frame rate (per second) for an output QT or AVI movie 00351 if (sscanf(argv[2], "%u", &movieFPS) != 1) { 00352 usage(); 00353 } 00354 movieFPSOptionSet = True; 00355 ++argv; --argc; 00356 break; 00357 } 00358 00359 case 'F': { // specify a prefix for the audio and video output files 00360 fileNamePrefix = argv[2]; 00361 ++argv; --argc; 00362 break; 00363 } 00364 00365 case 'b': { // specify the size of buffers for "FileSink"s 00366 if (sscanf(argv[2], "%u", &fileSinkBufferSize) != 1) { 00367 usage(); 00368 } 00369 ++argv; --argc; 00370 break; 00371 } 00372 00373 case 'B': { // specify the size of input socket buffers 00374 if (sscanf(argv[2], "%u", &socketInputBufferSize) != 1) { 00375 usage(); 00376 } 00377 ++argv; --argc; 00378 break; 00379 } 00380 00381 // Note: The following option is deprecated, and may someday be removed: 00382 case 'l': { // try to compensate for packet loss by repeating frames 00383 packetLossCompensate = True; 00384 break; 00385 } 00386 00387 case 'y': { // synchronize audio and video streams 00388 syncStreams = True; 00389 break; 00390 } 00391 00392 case 'H': { // generate hint tracks (as well as the regular data tracks) 00393 generateHintTracks = True; 00394 break; 00395 } 00396 00397 case 'Q': { // output QOS measurements 00398 qosMeasurementIntervalMS = 1000; // default: 1 second 00399 00400 if (argc > 3 && argv[2][0] != '-') { 00401 // The next argument is the measurement interval, 00402 // in multiples of 100 ms 00403 if (sscanf(argv[2], "%u", &qosMeasurementIntervalMS) != 1) { 00404 usage(); 00405 } 00406 qosMeasurementIntervalMS *= 100; 00407 ++argv; --argc; 00408 } 00409 break; 00410 } 00411 00412 case 's': { // specify initial seek time (trick play) 00413 float arg; 00414 if (sscanf(argv[2], "%g", &arg) != 1 || arg < 0) { 00415 usage(); 00416 } 00417 initialSeekTime = arg; 00418 ++argv; --argc; 00419 break; 00420 } 00421 00422 case 'z': { // scale (trick play) 00423 float arg; 00424 if (sscanf(argv[2], "%g", &arg) != 1 || arg == 0.0f) { 00425 usage(); 00426 } 00427 scale = arg; 00428 ++argv; --argc; 00429 break; 00430 } 00431 00432 default: { 00433 usage(); 00434 break; 00435 } 00436 } 00437 00438 ++argv; --argc; 00439 } 00440 if (argc != 2) usage(); 00441 if (outputQuickTimeFile && outputAVIFile) { 00442 *env << "The -i and -q (or -4) flags cannot both be used!\n"; 00443 usage(); 00444 } 00445 Boolean outputCompositeFile = outputQuickTimeFile || outputAVIFile; 00446 if (!createReceivers && outputCompositeFile) { 00447 *env << "The -r and -q (or -4 or -i) flags cannot both be used!\n"; 00448 usage(); 00449 } 00450 if (outputCompositeFile && !movieWidthOptionSet) { 00451 *env << "Warning: The -q, -4 or -i option was used, but not -w. Assuming a video width of " 00452 << movieWidth << " pixels\n"; 00453 } 00454 if (outputCompositeFile && !movieHeightOptionSet) { 00455 *env << "Warning: The -q, -4 or -i option was used, but not -h. Assuming a video height of " 00456 << movieHeight << " pixels\n"; 00457 } 00458 if (outputCompositeFile && !movieFPSOptionSet) { 00459 *env << "Warning: The -q, -4 or -i option was used, but not -f. Assuming a video frame rate of " 00460 << movieFPS << " frames-per-second\n"; 00461 } 00462 if (audioOnly && videoOnly) { 00463 *env << "The -a and -v flags cannot both be used!\n"; 00464 usage(); 00465 } 00466 if (sendOptionsRequestOnly && !sendOptionsRequest) { 00467 *env << "The -o and -O flags cannot both be used!\n"; 00468 usage(); 00469 } 00470 if (tunnelOverHTTPPortNum > 0) { 00471 if (streamUsingTCP) { 00472 *env << "The -t and -T flags cannot both be used!\n"; 00473 usage(); 00474 } else { 00475 streamUsingTCP = True; 00476 } 00477 } 00478 if (!createReceivers && notifyOnPacketArrival) { 00479 *env << "Warning: Because we're not receiving stream data, the -n flag has no effect\n"; 00480 } 00481 if (durationSlop < 0) { 00482 // This parameter wasn't set, so use a default value. 00483 // If we're measuring QOS stats, then don't add any slop, to avoid 00484 // having 'empty' measurement intervals at the end. 00485 durationSlop = qosMeasurementIntervalMS > 0 ? 0.0 : 5.0; 00486 } 00487 00488 char* url = argv[1]; 00489 00490 // Create our client object: 00491 ourClient = createClient(*env, verbosityLevel, progName); 00492 if (ourClient == NULL) { 00493 *env << "Failed to create " << clientProtocolName 00494 << " client: " << env->getResultMsg() << "\n"; 00495 shutdown(); 00496 } 00497 00498 if (sendOptionsRequest) { 00499 // Begin by sending an "OPTIONS" command: 00500 char* optionsResponse 00501 = getOptionsResponse(ourClient, url, username, password); 00502 if (sendOptionsRequestOnly) { 00503 if (optionsResponse == NULL) { 00504 *env << clientProtocolName << " \"OPTIONS\" request failed: " 00505 << env->getResultMsg() << "\n"; 00506 } else { 00507 *env << clientProtocolName << " \"OPTIONS\" request returned: " 00508 << optionsResponse << "\n"; 00509 } 00510 shutdown(); 00511 } 00512 delete[] optionsResponse; 00513 } 00514 00515 // Open the URL, to get a SDP description: 00516 char* sdpDescription 00517 = getSDPDescriptionFromURL(ourClient, url, username, password, 00518 proxyServerName, proxyServerPortNum, 00519 desiredPortNum); 00520 if (sdpDescription == NULL) { 00521 *env << "Failed to get a SDP description from URL \"" << url 00522 << "\": " << env->getResultMsg() << "\n"; 00523 shutdown(); 00524 } 00525 00526 *env << "Opened URL \"" << url 00527 << "\", returning a SDP description:\n" << sdpDescription << "\n"; 00528 00529 // Create a media session object from this SDP description: 00530 session = MediaSession::createNew(*env, sdpDescription); 00531 delete[] sdpDescription; 00532 if (session == NULL) { 00533 *env << "Failed to create a MediaSession object from the SDP description: " << env->getResultMsg() << "\n"; 00534 shutdown(); 00535 } else if (!session->hasSubsessions()) { 00536 *env << "This session has no media subsessions (i.e., \"m=\" lines)\n"; 00537 shutdown(); 00538 } 00539 00540 // Then, setup the "RTPSource"s for the session: 00541 MediaSubsessionIterator iter(*session); 00542 MediaSubsession *subsession; 00543 Boolean madeProgress = False; 00544 char const* singleMediumToTest = singleMedium; 00545 while ((subsession = iter.next()) != NULL) { 00546 // If we've asked to receive only a single medium, then check this now: 00547 if (singleMediumToTest != NULL) { 00548 if (strcmp(subsession->mediumName(), singleMediumToTest) != 0) { 00549 *env << "Ignoring \"" << subsession->mediumName() 00550 << "/" << subsession->codecName() 00551 << "\" subsession, because we've asked to receive a single " << singleMedium 00552 << " session only\n"; 00553 continue; 00554 } else { 00555 // Receive this subsession only 00556 singleMediumToTest = "xxxxx"; 00557 // this hack ensures that we get only 1 subsession of this type 00558 } 00559 } 00560 00561 if (desiredPortNum != 0) { 00562 subsession->setClientPortNum(desiredPortNum); 00563 desiredPortNum += 2; 00564 } 00565 00566 if (createReceivers) { 00567 if (!subsession->initiate(simpleRTPoffsetArg)) { 00568 *env << "Unable to create receiver for \"" << subsession->mediumName() 00569 << "/" << subsession->codecName() 00570 << "\" subsession: " << env->getResultMsg() << "\n"; 00571 } else { 00572 *env << "Created receiver for \"" << subsession->mediumName() 00573 << "/" << subsession->codecName() 00574 << "\" subsession (client ports " << subsession->clientPortNum() 00575 << "-" << subsession->clientPortNum()+1 << ")\n"; 00576 madeProgress = True; 00577 00578 if (subsession->rtpSource() != NULL) { 00579 // Because we're saving the incoming data, rather than playing 00580 // it in real time, allow an especially large time threshold 00581 // (1 second) for reordering misordered incoming packets: 00582 unsigned const thresh = 1000000; // 1 second 00583 subsession->rtpSource()->setPacketReorderingThresholdTime(thresh); 00584 00585 if (socketInputBufferSize > 0) { 00586 // Set the RTP source's input buffer size as specified: 00587 int socketNum 00588 = subsession->rtpSource()->RTPgs()->socketNum(); 00589 unsigned curBufferSize 00590 = getReceiveBufferSize(*env, socketNum); 00591 unsigned newBufferSize 00592 = setReceiveBufferTo(*env, socketNum, socketInputBufferSize); 00593 *env << "Changed socket receive buffer size for the \"" 00594 << subsession->mediumName() 00595 << "/" << subsession->codecName() 00596 << "\" subsession from " 00597 << curBufferSize << " to " 00598 << newBufferSize << " bytes\n"; 00599 } 00600 } 00601 } 00602 } else { 00603 if (subsession->clientPortNum() == 0) { 00604 *env << "No client port was specified for the \"" 00605 << subsession->mediumName() 00606 << "/" << subsession->codecName() 00607 << "\" subsession. (Try adding the \"-p <portNum>\" option.)\n"; 00608 } else { 00609 madeProgress = True; 00610 } 00611 } 00612 } 00613 if (!madeProgress) shutdown(); 00614 00615 // Perform additional 'setup' on each subsession, before playing them: 00616 setupStreams();