#include <RTSPClient.hh>
Inheritance diagram for RTSPClient:


Public Types | |
| typedef void( | responseHandler )(RTSPClient *rtspClient, int resultCode, char *resultString) |
Public Member Functions | |
| unsigned | sendDescribeCommand (responseHandler *responseHandler, Authenticator *authenticator=NULL) |
| unsigned | sendOptionsCommand (responseHandler *responseHandler, Authenticator *authenticator=NULL) |
| unsigned | sendAnnounceCommand (char const *sdpDescription, responseHandler *responseHandler, Authenticator *authenticator=NULL) |
| unsigned | sendSetupCommand (MediaSubsession &subsession, responseHandler *responseHandler, Boolean streamOutgoing=False, Boolean streamUsingTCP=False, Boolean forceMulticastOnUnspecified=False, Authenticator *authenticator=NULL) |
| unsigned | sendPlayCommand (MediaSession &session, responseHandler *responseHandler, double start=0.0f, double end=-1.0f, float scale=1.0f, Authenticator *authenticator=NULL) |
| unsigned | sendPlayCommand (MediaSubsession &subsession, responseHandler *responseHandler, double start=0.0f, double end=-1.0f, float scale=1.0f, Authenticator *authenticator=NULL) |
| unsigned | sendPlayCommand (MediaSession &session, responseHandler *responseHandler, char const *absStartTime, char const *absEndTime=NULL, float scale=1.0f, Authenticator *authenticator=NULL) |
| unsigned | sendPlayCommand (MediaSubsession &subsession, responseHandler *responseHandler, char const *absStartTime, char const *absEndTime=NULL, float scale=1.0f, Authenticator *authenticator=NULL) |
| unsigned | sendPauseCommand (MediaSession &session, responseHandler *responseHandler, Authenticator *authenticator=NULL) |
| unsigned | sendPauseCommand (MediaSubsession &subsession, responseHandler *responseHandler, Authenticator *authenticator=NULL) |
| unsigned | sendRecordCommand (MediaSession &session, responseHandler *responseHandler, Authenticator *authenticator=NULL) |
| unsigned | sendRecordCommand (MediaSubsession &subsession, responseHandler *responseHandler, Authenticator *authenticator=NULL) |
| unsigned | sendTeardownCommand (MediaSession &session, responseHandler *responseHandler, Authenticator *authenticator=NULL) |
| unsigned | sendTeardownCommand (MediaSubsession &subsession, responseHandler *responseHandler, Authenticator *authenticator=NULL) |
| unsigned | sendSetParameterCommand (MediaSession &session, responseHandler *responseHandler, char const *parameterName, char const *parameterValue, Authenticator *authenticator=NULL) |
| unsigned | sendGetParameterCommand (MediaSession &session, responseHandler *responseHandler, char const *parameterName, Authenticator *authenticator=NULL) |
| Boolean | changeResponseHandler (unsigned cseq, responseHandler *newResponseHandler) |
| int | socketNum () const |
| void | setUserAgentString (char const *userAgentName) |
| unsigned | sessionTimeoutParameter () const |
| char const * | url () const |
| UsageEnvironment & | envir () const |
| char const * | name () const |
| virtual Boolean | isSource () const |
| virtual Boolean | isSink () const |
| virtual Boolean | isRTCPInstance () const |
| virtual Boolean | isRTSPServer () const |
| virtual Boolean | isMediaSession () const |
| virtual Boolean | isServerMediaSession () const |
| virtual Boolean | isDarwinInjector () const |
Static Public Member Functions | |
| static RTSPClient * | createNew (UsageEnvironment &env, char const *rtspURL, int verbosityLevel=0, char const *applicationName=NULL, portNumBits tunnelOverHTTPPortNum=0, int socketNumToServer=-1) |
| static Boolean | lookupByName (UsageEnvironment &env, char const *sourceName, RTSPClient *&resultClient) |
| static Boolean | parseRTSPURL (UsageEnvironment &env, char const *url, char *&username, char *&password, NetAddress &address, portNumBits &portNum, char const **urlSuffix=NULL) |
| static Boolean | lookupByName (UsageEnvironment &env, char const *mediumName, Medium *&resultMedium) |
| static void | close (UsageEnvironment &env, char const *mediumName) |
| static void | close (Medium *medium) |
Static Public Attributes | |
| static unsigned | responseBufferSize = 20000 |
Protected Member Functions | |
| RTSPClient (UsageEnvironment &env, char const *rtspURL, int verbosityLevel, char const *applicationName, portNumBits tunnelOverHTTPPortNum, int socketNumToServer) | |
| virtual | ~RTSPClient () |
| void | reset () |
| void | setBaseURL (char const *url) |
| virtual unsigned | sendRequest (RequestRecord *request) |
| TaskToken & | nextTask () |
Protected Attributes | |
| int | fVerbosityLevel |
| unsigned | fCSeq |
| Authenticator | fCurrentAuthenticator |
Private Member Functions | |
| virtual Boolean | isRTSPClient () const |
| void | resetTCPSockets () |
| void | resetResponseBuffer () |
| int | openConnection () |
| int | connectToServer (int socketNum, portNumBits remotePortNum) |
| char * | createAuthenticatorString (char const *cmd, char const *url) |
| void | handleRequestError (RequestRecord *request) |
| Boolean | parseResponseCode (char const *line, unsigned &responseCode, char const *&responseString) |
| void | handleIncomingRequest () |
| Boolean | parseTransportParams (char const *paramsStr, char *&serverAddressStr, portNumBits &serverPortNum, unsigned char &rtpChannelId, unsigned char &rtcpChannelId) |
| Boolean | parseScaleParam (char const *paramStr, float &scale) |
| Boolean | parseRTPInfoParams (char const *¶mStr, u_int16_t &seqNum, u_int32_t ×tamp) |
| Boolean | handleSETUPResponse (MediaSubsession &subsession, char const *sessionParamsStr, char const *transportParamsStr, Boolean streamUsingTCP) |
| Boolean | handlePLAYResponse (MediaSession &session, MediaSubsession &subsession, char const *scaleParamsStr, char const *rangeParamsStr, char const *rtpInfoParamsStr) |
| Boolean | handleTEARDOWNResponse (MediaSession &session, MediaSubsession &subsession) |
| Boolean | handleGET_PARAMETERResponse (char const *parameterName, char *&resultValueString) |
| Boolean | handleAuthenticationFailure (char const *wwwAuthenticateParamsStr) |
| Boolean | resendCommand (RequestRecord *request) |
| char const * | sessionURL (MediaSession const &session) const |
| void | handleAlternativeRequestByte1 (u_int8_t requestByte) |
| void | constructSubsessionURL (MediaSubsession const &subsession, char const *&prefix, char const *&separator, char const *&suffix) |
| Boolean | setupHTTPTunneling1 () |
| void | responseHandlerForHTTP_GET1 (int responseCode, char *responseString) |
| Boolean | setupHTTPTunneling2 () |
| void | connectionHandler1 () |
| void | incomingDataHandler1 () |
| void | handleResponseBytes (int newBytesRead) |
Static Private Member Functions | |
| static Boolean | checkForHeader (char const *line, char const *headerName, unsigned headerNameLength, char const *&headerParams) |
| static void | handleAlternativeRequestByte (void *, u_int8_t requestByte) |
| static void | responseHandlerForHTTP_GET (RTSPClient *rtspClient, int responseCode, char *responseString) |
| static void | connectionHandler (void *, int) |
| static void | incomingDataHandler (void *, int) |
Private Attributes | |
| portNumBits | fTunnelOverHTTPPortNum |
| char * | fUserAgentHeaderStr |
| unsigned | fUserAgentHeaderStrLen |
| int | fInputSocketNum |
| int | fOutputSocketNum |
| netAddressBits | fServerAddress |
| char * | fBaseURL |
| unsigned char | fTCPStreamIdCount |
| char * | fLastSessionId |
| unsigned | fSessionTimeoutParameter |
| char * | fResponseBuffer |
| unsigned | fResponseBytesAlreadySeen |
| unsigned | fResponseBufferBytesLeft |
| RequestQueue | fRequestsAwaitingConnection |
| RequestQueue | fRequestsAwaitingHTTPTunneling |
| RequestQueue | fRequestsAwaitingResponse |
| char | fSessionCookie [33] |
| unsigned | fSessionCookieCounter |
| Boolean | fHTTPTunnelingConnectionIsPending |
Friends | |
| class | MediaLookupTable |
Data Structures | |
| class | RequestQueue |
| class | RequestRecord |
Definition at line 37 of file RTSPClient.hh.
| typedef void( RTSPClient::responseHandler)(RTSPClient *rtspClient, int resultCode, char *resultString) |
Definition at line 50 of file RTSPClient.hh.
| RTSPClient::RTSPClient | ( | UsageEnvironment & | env, | |
| char const * | rtspURL, | |||
| int | verbosityLevel, | |||
| char const * | applicationName, | |||
| portNumBits | tunnelOverHTTPPortNum, | |||
| int | socketNumToServer | |||
| ) | [protected] |
Definition at line 297 of file RTSPClient.cpp.
References Medium::envir(), fInputSocketNum, fOutputSocketNum, fResponseBuffer, incomingDataHandler(), libVersionStr, LIVEMEDIA_LIBRARY_VERSION_STRING, NULL, resetResponseBuffer(), responseBufferSize, TaskScheduler::setBackgroundHandling(), setBaseURL(), setUserAgentString(), SOCKET_EXCEPTION, SOCKET_READABLE, and UsageEnvironment::taskScheduler().
Referenced by createNew().
00300 : Medium(env), 00301 fVerbosityLevel(verbosityLevel), fCSeq(1), 00302 fTunnelOverHTTPPortNum(tunnelOverHTTPPortNum), fUserAgentHeaderStr(NULL), fUserAgentHeaderStrLen(0), 00303 fInputSocketNum(-1), fOutputSocketNum(-1), fServerAddress(0), fBaseURL(NULL), fTCPStreamIdCount(0), 00304 fLastSessionId(NULL), fSessionTimeoutParameter(0), fSessionCookieCounter(0), fHTTPTunnelingConnectionIsPending(False) { 00305 setBaseURL(rtspURL); 00306 00307 fResponseBuffer = new char[responseBufferSize+1]; 00308 resetResponseBuffer(); 00309 00310 if (socketNumToServer >= 0) { 00311 // This socket number is (assumed to be) already connected to the server. 00312 // Use it, and arrange to handle responses to requests sent on it: 00313 fInputSocketNum = fOutputSocketNum = socketNumToServer; 00314 envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE|SOCKET_EXCEPTION, 00315 (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this); 00316 } 00317 00318 // Set the "User-Agent:" header to use in each request: 00319 char const* const libName = "LIVE555 Streaming Media v"; 00320 char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING; 00321 char const* libPrefix; char const* libSuffix; 00322 if (applicationName == NULL || applicationName[0] == '\0') { 00323 applicationName = libPrefix = libSuffix = ""; 00324 } else { 00325 libPrefix = " ("; 00326 libSuffix = ")"; 00327 } 00328 unsigned userAgentNameSize 00329 = strlen(applicationName) + strlen(libPrefix) + strlen(libName) + strlen(libVersionStr) + strlen(libSuffix) + 1; 00330 char* userAgentName = new char[userAgentNameSize]; 00331 sprintf(userAgentName, "%s%s%s%s%s", applicationName, libPrefix, libName, libVersionStr, libSuffix); 00332 setUserAgentString(userAgentName); 00333 delete[] userAgentName; 00334 }
| RTSPClient::~RTSPClient | ( | ) | [protected, virtual] |
Definition at line 336 of file RTSPClient.cpp.
References fResponseBuffer, fUserAgentHeaderStr, and reset().
00336 { 00337 reset(); 00338 00339 delete[] fResponseBuffer; 00340 delete[] fUserAgentHeaderStr; 00341 }
| RTSPClient * RTSPClient::createNew | ( | UsageEnvironment & | env, | |
| char const * | rtspURL, | |||
| int | verbosityLevel = 0, |
|||
| char const * | applicationName = NULL, |
|||
| portNumBits | tunnelOverHTTPPortNum = 0, |
|||
| int | socketNumToServer = -1 | |||
| ) | [static] |
Definition at line 30 of file RTSPClient.cpp.
References env, and RTSPClient().
Referenced by createClient(), HandlerServerForREGISTERCommand::createNewRTSPClient(), and ProxyServerMediaSubsession::createNewStreamSource().
00034 { 00035 return new RTSPClient(env, rtspURL, 00036 verbosityLevel, applicationName, tunnelOverHTTPPortNum, socketNumToServer); 00037 }
| unsigned RTSPClient::sendDescribeCommand | ( | responseHandler * | responseHandler, | |
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 39 of file RTSPClient.cpp.
References fCSeq, fCurrentAuthenticator, NULL, and sendRequest().
Referenced by getSDPDescription(), openURL(), and ProxyRTSPClient::sendDESCRIBE().
00039 { 00040 if (authenticator != NULL) fCurrentAuthenticator = *authenticator; 00041 return sendRequest(new RequestRecord(++fCSeq, "DESCRIBE", responseHandler)); 00042 }
| unsigned RTSPClient::sendOptionsCommand | ( | responseHandler * | responseHandler, | |
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 44 of file RTSPClient.cpp.
References fCSeq, fCurrentAuthenticator, NULL, and sendRequest().
Referenced by getOptions(), and ProxyRTSPClient::sendLivenessCommand().
00044 { 00045 if (authenticator != NULL) fCurrentAuthenticator = *authenticator; 00046 return sendRequest(new RequestRecord(++fCSeq, "OPTIONS", responseHandler)); 00047 }
| unsigned RTSPClient::sendAnnounceCommand | ( | char const * | sdpDescription, | |
| responseHandler * | responseHandler, | |||
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 49 of file RTSPClient.cpp.
References False, fCSeq, fCurrentAuthenticator, NULL, and sendRequest().
Referenced by DarwinInjector::setDestination().
00049 { 00050 if (authenticator != NULL) fCurrentAuthenticator = *authenticator; 00051 return sendRequest(new RequestRecord(++fCSeq, "ANNOUNCE", responseHandler, NULL, NULL, False, 0.0, 0.0, 0.0, sdpDescription)); 00052 }
| unsigned RTSPClient::sendSetupCommand | ( | MediaSubsession & | subsession, | |
| responseHandler * | responseHandler, | |||
| Boolean | streamOutgoing = False, |
|||
| Boolean | streamUsingTCP = False, |
|||
| Boolean | forceMulticastOnUnspecified = False, |
|||
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 54 of file RTSPClient.cpp.
References fCSeq, fCurrentAuthenticator, fTunnelOverHTTPPortNum, NULL, sendRequest(), subsession, and True.
Referenced by ProxyRTSPClient::continueAfterSETUP(), ProxyServerMediaSubsession::createNewStreamSource(), DarwinInjector::setDestination(), setupNextSubsession(), and setupSubsession().
00056 { 00057 if (fTunnelOverHTTPPortNum != 0) streamUsingTCP = True; // RTSP-over-HTTP tunneling uses TCP (by definition) 00058 if (authenticator != NULL) fCurrentAuthenticator = *authenticator; 00059 00060 u_int32_t booleanFlags = 0; 00061 if (streamUsingTCP) booleanFlags |= 0x1; 00062 if (streamOutgoing) booleanFlags |= 0x2; 00063 if (forceMulticastOnUnspecified) booleanFlags |= 0x4; 00064 return sendRequest(new RequestRecord(++fCSeq, "SETUP", responseHandler, NULL, &subsession, booleanFlags)); 00065 }
| unsigned RTSPClient::sendPlayCommand | ( | MediaSession & | session, | |
| responseHandler * | responseHandler, | |||
| double | start = 0.0f, |
|||
| double | end = -1.0f, |
|||
| float | scale = 1.0f, |
|||
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 67 of file RTSPClient.cpp.
References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and session.
Referenced by ProxyRTSPClient::continueAfterSETUP(), ProxyServerMediaSubsession::createNewStreamSource(), ProxyRTSPClient::handleSubsessionTimeout(), DarwinInjector::setDestination(), setupNextSubsession(), and startPlayingSession().
00069 { 00070 if (authenticator != NULL) fCurrentAuthenticator = *authenticator; 00071 return sendRequest(new RequestRecord(++fCSeq, "PLAY", responseHandler, &session, NULL, 0, start, end, scale)); 00072 }
| unsigned RTSPClient::sendPlayCommand | ( | MediaSubsession & | subsession, | |
| responseHandler * | responseHandler, | |||
| double | start = 0.0f, |
|||
| double | end = -1.0f, |
|||
| float | scale = 1.0f, |
|||
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 74 of file RTSPClient.cpp.
References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and subsession.
00076 { 00077 if (authenticator != NULL) fCurrentAuthenticator = *authenticator; 00078 return sendRequest(new RequestRecord(++fCSeq, "PLAY", responseHandler, NULL, &subsession, 0, start, end, scale)); 00079 }
| unsigned RTSPClient::sendPlayCommand | ( | MediaSession & | session, | |
| responseHandler * | responseHandler, | |||
| char const * | absStartTime, | |||
| char const * | absEndTime = NULL, |
|||
| float | scale = 1.0f, |
|||
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 81 of file RTSPClient.cpp.
References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and session.
00083 { 00084 if (authenticator != NULL) fCurrentAuthenticator = *authenticator; 00085 return sendRequest(new RequestRecord(++fCSeq, responseHandler, absStartTime, absEndTime, scale, &session, NULL)); 00086 }
| unsigned RTSPClient::sendPlayCommand | ( | MediaSubsession & | subsession, | |
| responseHandler * | responseHandler, | |||
| char const * | absStartTime, | |||
| char const * | absEndTime = NULL, |
|||
| float | scale = 1.0f, |
|||
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 88 of file RTSPClient.cpp.
References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and subsession.
00090 { 00091 if (authenticator != NULL) fCurrentAuthenticator = *authenticator; 00092 return sendRequest(new RequestRecord(++fCSeq, responseHandler, absStartTime, absEndTime, scale, NULL, &subsession)); 00093 }
| unsigned RTSPClient::sendPauseCommand | ( | MediaSession & | session, | |
| responseHandler * | responseHandler, | |||
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 95 of file RTSPClient.cpp.
References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and session.
Referenced by ProxyServerMediaSubsession::closeStreamSource().
00095 { 00096 if (authenticator != NULL) fCurrentAuthenticator = *authenticator; 00097 return sendRequest(new RequestRecord(++fCSeq, "PAUSE", responseHandler, &session)); 00098 }
| unsigned RTSPClient::sendPauseCommand | ( | MediaSubsession & | subsession, | |
| responseHandler * | responseHandler, | |||
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 100 of file RTSPClient.cpp.
References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and subsession.
00100 { 00101 if (authenticator != NULL) fCurrentAuthenticator = *authenticator; 00102 return sendRequest(new RequestRecord(++fCSeq, "PAUSE", responseHandler, NULL, &subsession)); 00103 }
| unsigned RTSPClient::sendRecordCommand | ( | MediaSession & | session, | |
| responseHandler * | responseHandler, | |||
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 105 of file RTSPClient.cpp.
References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and session.
00105 { 00106 if (authenticator != NULL) fCurrentAuthenticator = *authenticator; 00107 return sendRequest(new RequestRecord(++fCSeq, "RECORD", responseHandler, &session)); 00108 }
| unsigned RTSPClient::sendRecordCommand | ( | MediaSubsession & | subsession, | |
| responseHandler * | responseHandler, | |||
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 110 of file RTSPClient.cpp.
References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and subsession.
00110 { 00111 if (authenticator != NULL) fCurrentAuthenticator = *authenticator; 00112 return sendRequest(new RequestRecord(++fCSeq, "RECORD", responseHandler, NULL, &subsession)); 00113 }
| unsigned RTSPClient::sendTeardownCommand | ( | MediaSession & | session, | |
| responseHandler * | responseHandler, | |||
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 115 of file RTSPClient.cpp.
References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and session.
Referenced by shutdownStream(), tearDownSession(), DarwinInjector::~DarwinInjector(), and ProxyServerMediaSession::~ProxyServerMediaSession().
00115 { 00116 if (authenticator != NULL) fCurrentAuthenticator = *authenticator; 00117 return sendRequest(new RequestRecord(++fCSeq, "TEARDOWN", responseHandler, &session)); 00118 }
| unsigned RTSPClient::sendTeardownCommand | ( | MediaSubsession & | subsession, | |
| responseHandler * | responseHandler, | |||
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 120 of file RTSPClient.cpp.
References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and subsession.
00120 { 00121 if (authenticator != NULL) fCurrentAuthenticator = *authenticator; 00122 return sendRequest(new RequestRecord(++fCSeq, "TEARDOWN", responseHandler, NULL, &subsession)); 00123 }
| unsigned RTSPClient::sendSetParameterCommand | ( | MediaSession & | session, | |
| responseHandler * | responseHandler, | |||
| char const * | parameterName, | |||
| char const * | parameterValue, | |||
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 125 of file RTSPClient.cpp.
References False, fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and session.
00127 { 00128 if (authenticator != NULL) fCurrentAuthenticator = *authenticator; 00129 char* paramString = new char[strlen(parameterName) + strlen(parameterValue) + 10]; 00130 sprintf(paramString, "%s: %s\r\n", parameterName, parameterValue); 00131 unsigned result = sendRequest(new RequestRecord(++fCSeq, "SET_PARAMETER", responseHandler, &session, NULL, False, 0.0, 0.0, 0.0, paramString)); 00132 delete[] paramString; 00133 return result; 00134 }
| unsigned RTSPClient::sendGetParameterCommand | ( | MediaSession & | session, | |
| responseHandler * | responseHandler, | |||
| char const * | parameterName, | |||
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 136 of file RTSPClient.cpp.
References False, fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and session.
Referenced by ProxyRTSPClient::sendLivenessCommand().
00137 { 00138 if (authenticator != NULL) fCurrentAuthenticator = *authenticator; 00139 00140 // We assume that: 00141 // parameterName is NULL means: Send no body in the request. 00142 // parameterName is "" means: Send only \r\n in the request body. 00143 // parameterName is non-empty means: Send "<parameterName>\r\n" as the request body. 00144 unsigned parameterNameLen = parameterName == NULL ? 0 : strlen(parameterName); 00145 char* paramString = new char[parameterNameLen + 3]; // the 3 is for \r\n + the '\0' byte 00146 if (parameterName == NULL) { 00147 paramString[0] = '\0'; 00148 } else { 00149 sprintf(paramString, "%s\r\n", parameterName); 00150 } 00151 unsigned result = sendRequest(new RequestRecord(++fCSeq, "GET_PARAMETER", responseHandler, &session, NULL, False, 0.0, 0.0, 0.0, paramString)); 00152 delete[] paramString; 00153 return result; 00154 }
| Boolean RTSPClient::changeResponseHandler | ( | unsigned | cseq, | |
| responseHandler * | newResponseHandler | |||
| ) |
Definition at line 156 of file RTSPClient.cpp.
References False, RTSPClient::RequestQueue::findByCSeq(), fRequestsAwaitingConnection, fRequestsAwaitingHTTPTunneling, fRequestsAwaitingResponse, RTSPClient::RequestRecord::handler(), NULL, and True.
00156 { 00157 // Look for the matching request record in each of our 'pending requests' queues: 00158 RequestRecord* request; 00159 if ((request = fRequestsAwaitingConnection.findByCSeq(cseq)) != NULL 00160 || (request = fRequestsAwaitingHTTPTunneling.findByCSeq(cseq)) != NULL 00161 || (request = fRequestsAwaitingResponse.findByCSeq(cseq)) != NULL) { 00162 request->handler() = newResponseHandler; 00163 return True; 00164 } 00165 00166 return False; 00167 }
| int RTSPClient::socketNum | ( | ) | const [inline] |
Definition at line 154 of file RTSPClient.hh.
References fInputSocketNum.
Referenced by DarwinInjector::setDestination().
00154 { return fInputSocketNum; }
| Boolean RTSPClient::lookupByName | ( | UsageEnvironment & | env, | |
| char const * | sourceName, | |||
| RTSPClient *& | resultClient | |||
| ) | [static] |
Definition at line 169 of file RTSPClient.cpp.
References env, False, Medium::isRTSPClient(), Medium::lookupByName(), NULL, and True.
00171 { 00172 resultClient = NULL; // unless we succeed 00173 00174 Medium* medium; 00175 if (!Medium::lookupByName(env, instanceName, medium)) return False; 00176 00177 if (!medium->isRTSPClient()) { 00178 env.setResultMsg(instanceName, " is not a RTSP client"); 00179 return False; 00180 } 00181 00182 resultClient = (RTSPClient*)medium; 00183 return True; 00184 }
| Boolean RTSPClient::parseRTSPURL | ( | UsageEnvironment & | env, | |
| char const * | url, | |||
| char *& | username, | |||
| char *& | password, | |||
| NetAddress & | address, | |||
| portNumBits & | portNum, | |||
| char const ** | urlSuffix = NULL | |||
| ) | [static] |
Definition at line 186 of file RTSPClient.cpp.
References _strncasecmp, env, False, NetAddressList::firstAddress(), NULL, NetAddressList::numAddresses(), UsageEnvironment::setResultMsg(), and True.
Referenced by openConnection(), and sendRequest().
00190 { 00191 do { 00192 // Parse the URL as "rtsp://[<username>[:<password>]@]<server-address-or-name>[:<port>][/<stream-name>]" 00193 char const* prefix = "rtsp://"; 00194 unsigned const prefixLength = 7; 00195 if (_strncasecmp(url, prefix, prefixLength) != 0) { 00196 env.setResultMsg("URL is not of the form \"", prefix, "\""); 00197 break; 00198 } 00199 00200 unsigned const parseBufferSize = 100; 00201 char parseBuffer[parseBufferSize]; 00202 char const* from = &url[prefixLength]; 00203 00204 // Check whether "<username>[:<password>]@" occurs next. 00205 // We do this by checking whether '@' appears before the end of the URL, or before the first '/'. 00206 username = password = NULL; // default return values 00207 char const* colonPasswordStart = NULL; 00208 char const* p; 00209 for (p = from; *p != '\0' && *p != '/'; ++p) { 00210 if (*p == ':' && colonPasswordStart == NULL) { 00211 colonPasswordStart = p; 00212 } else if (*p == '@') { 00213 // We found <username> (and perhaps <password>). Copy them into newly-allocated result strings: 00214 if (colonPasswordStart == NULL) colonPasswordStart = p; 00215 00216 char const* usernameStart = from; 00217 unsigned usernameLen = colonPasswordStart - usernameStart; 00218 username = new char[usernameLen + 1] ; // allow for the trailing '\0' 00219 for (unsigned i = 0; i < usernameLen; ++i) username[i] = usernameStart[i]; 00220 username[usernameLen] = '\0'; 00221 00222 char const* passwordStart = colonPasswordStart; 00223 if (passwordStart < p) ++passwordStart; // skip over the ':' 00224 unsigned passwordLen = p - passwordStart; 00225 password = new char[passwordLen + 1]; // allow for the trailing '\0' 00226 for (unsigned j = 0; j < passwordLen; ++j) password[j] = passwordStart[j]; 00227 password[passwordLen] = '\0'; 00228 00229 from = p + 1; // skip over the '@' 00230 break; 00231 } 00232 } 00233 00234 // Next, parse <server-address-or-name> 00235 char* to = &parseBuffer[0]; 00236 unsigned i; 00237 for (i = 0; i < parseBufferSize; ++i) { 00238 if (*from == '\0' || *from == ':' || *from == '/') { 00239 // We've completed parsing the address 00240 *to = '\0'; 00241 break; 00242 } 00243 *to++ = *from++; 00244 } 00245 if (i == parseBufferSize) { 00246 env.setResultMsg("URL is too long"); 00247 break; 00248 } 00249 00250 NetAddressList addresses(parseBuffer); 00251 if (addresses.numAddresses() == 0) { 00252 env.setResultMsg("Failed to find network address for \"", 00253 parseBuffer, "\""); 00254 break; 00255 } 00256 address = *(addresses.firstAddress()); 00257 00258 portNum = 554; // default value 00259 char nextChar = *from; 00260 if (nextChar == ':') { 00261 int portNumInt; 00262 if (sscanf(++from, "%d", &portNumInt) != 1) { 00263 env.setResultMsg("No port number follows ':'"); 00264 break; 00265 } 00266 if (portNumInt < 1 || portNumInt > 65535) { 00267 env.setResultMsg("Bad port number"); 00268 break; 00269 } 00270 portNum = (portNumBits)portNumInt; 00271 while (*from >= '0' && *from <= '9') ++from; // skip over port number 00272 } 00273 00274 // The remainder of the URL is the suffix: 00275 if (urlSuffix != NULL) *urlSuffix = from; 00276 00277 return True; 00278 } while (0); 00279 00280 return False; 00281 }
| void RTSPClient::setUserAgentString | ( | char const * | userAgentName | ) |
Definition at line 283 of file RTSPClient.cpp.
References fUserAgentHeaderStr, fUserAgentHeaderStrLen, and NULL.
Referenced by RTSPClient().
00283 { 00284 if (userAgentName == NULL) return; 00285 00286 // Change the existing user agent header string: 00287 char const* const formatStr = "User-Agent: %s\r\n"; 00288 unsigned const headerSize = strlen(formatStr) + strlen(userAgentName); 00289 delete[] fUserAgentHeaderStr; 00290 fUserAgentHeaderStr = new char[headerSize]; 00291 sprintf(fUserAgentHeaderStr, formatStr, userAgentName); 00292 fUserAgentHeaderStrLen = strlen(fUserAgentHeaderStr); 00293 }
| unsigned RTSPClient::sessionTimeoutParameter | ( | ) | const [inline] |
Definition at line 168 of file RTSPClient.hh.
References fSessionTimeoutParameter.
Referenced by ProxyRTSPClient::scheduleLivenessCommand().
00168 { return fSessionTimeoutParameter; }
| char const* RTSPClient::url | ( | ) | const [inline] |
Definition at line 170 of file RTSPClient.hh.
References fBaseURL.
Referenced by continueAfterClientCreation0(), operator<<(), sessionURL(), and ProxyServerMediaSession::url().
00170 { return fBaseURL; }
| void RTSPClient::reset | ( | ) | [protected] |
Reimplemented in ProxyRTSPClient.
Definition at line 347 of file RTSPClient.cpp.
References fCurrentAuthenticator, fLastSessionId, fServerAddress, NULL, Authenticator::reset(), resetResponseBuffer(), resetTCPSockets(), and setBaseURL().
Referenced by ProxyRTSPClient::reset(), and ~RTSPClient().
00347 { 00348 resetTCPSockets(); 00349 resetResponseBuffer(); 00350 fServerAddress = 0; 00351 00352 setBaseURL(NULL); 00353 00354 fCurrentAuthenticator.reset(); 00355 00356 delete[] fLastSessionId; fLastSessionId = NULL; 00357 }
| void RTSPClient::setBaseURL | ( | char const * | url | ) | [protected] |
Definition at line 376 of file RTSPClient.cpp.
References fBaseURL, and strDup().
Referenced by ProxyRTSPClient::continueAfterLivenessCommand(), handleResponseBytes(), reset(), and RTSPClient().
| unsigned RTSPClient::sendRequest | ( | RequestRecord * | request | ) | [protected, virtual] |
Definition at line 537 of file RTSPClient.cpp.
References RTSPClient::RequestRecord::absEndTime(), RTSPClient::RequestRecord::absStartTime(), base64Encode(), RTSPClient::RequestRecord::booleanFlags(), MediaSubsession::clientPortNum(), RTSPClient::RequestRecord::commandName(), MediaSubsession::connectionEndpointAddress(), constructSubsessionURL(), RTSPClient::RequestRecord::contentStr(), createAuthenticatorString(), createRangeString(), createScaleString(), createSessionString(), RTSPClient::RequestRecord::cseq(), RTSPClient::RequestRecord::end(), RTSPClient::RequestQueue::enqueue(), Medium::envir(), False, fBaseURL, fInputSocketNum, fLastSessionId, fOutputSocketNum, fRequestsAwaitingConnection, fRequestsAwaitingHTTPTunneling, fRequestsAwaitingResponse, fSessionCookie, fSessionCookieCounter, fTCPStreamIdCount, fTunnelOverHTTPPortNum, fUserAgentHeaderStr, fUserAgentHeaderStrLen, fVerbosityLevel, handleRequestError(), RTSPClient::RequestQueue::isEmpty(), IsMulticastAddress(), NULL, openConnection(), our_MD5Data(), parseRTSPURL(), password, MediaSubsession::protocolName(), RTSPClient::RequestRecord::scale(), MediaSubsession::scale(), MediaSession::scale(), RTSPClient::RequestRecord::session(), MediaSubsession::sessionId(), sessionURL(), UsageEnvironment::setResultErrMsg(), UsageEnvironment::setResultMsg(), setupHTTPTunneling1(), RTSPClient::RequestRecord::start(), streamUsingTCP, RTSPClient::RequestRecord::subsession(), subsession, True, and username.
Referenced by connectionHandler1(), resendCommand(), responseHandlerForHTTP_GET1(), sendAnnounceCommand(), sendDescribeCommand(), sendGetParameterCommand(), sendOptionsCommand(), sendPauseCommand(), sendPlayCommand(), sendRecordCommand(), sendSetParameterCommand(), sendSetupCommand(), sendTeardownCommand(), setupHTTPTunneling1(), and setupHTTPTunneling2().
00537 { 00538 char* cmd = NULL; 00539 do { 00540 Boolean connectionIsPending = False; 00541 if (!fRequestsAwaitingConnection.isEmpty()) { 00542 // A connection is currently pending (with at least one enqueued request). Enqueue this request also: 00543 connectionIsPending = True; 00544 } else if (fInputSocketNum < 0) { // we need to open a connection 00545 int connectResult = openConnection(); 00546 if (connectResult < 0) break; // an error occurred 00547 else if (connectResult == 0) { 00548 // A connection is pending 00549 connectionIsPending = True; 00550 } // else the connection succeeded. Continue sending the command. 00551 } 00552 if (connectionIsPending) { 00553 fRequestsAwaitingConnection.enqueue(request); 00554 return request->cseq(); 00555 } 00556 00557 // If requested (and we're not already doing it, or have done it), set up the special protocol for tunneling RTSP-over-HTTP: 00558 if (fTunnelOverHTTPPortNum != 0 && strcmp(request->commandName(), "GET") != 0 && fOutputSocketNum == fInputSocketNum) { 00559 if (!setupHTTPTunneling1()) break; 00560 fRequestsAwaitingHTTPTunneling.enqueue(request); 00561 return request->cseq(); 00562 } 00563 00564 // Construct and send the command: 00565 00566 // First, construct command-specific headers that we need: 00567 00568 char* cmdURL = fBaseURL; // by default 00569 Boolean cmdURLWasAllocated = False; 00570 00571 char const* protocolStr = "RTSP/1.0"; // by default 00572 00573 char* extraHeaders = (char*)""; // by default 00574 Boolean extraHeadersWereAllocated = False; 00575 00576 char* contentLengthHeader = (char*)""; // by default 00577 Boolean contentLengthHeaderWasAllocated = False; 00578 00579 char const* contentStr = request->contentStr(); // by default 00580 if (contentStr == NULL) contentStr = ""; 00581 unsigned contentStrLen = strlen(contentStr); 00582 if (contentStrLen > 0) { 00583 char const* contentLengthHeaderFmt = 00584 "Content-Length: %d\r\n"; 00585 unsigned contentLengthHeaderSize = strlen(contentLengthHeaderFmt) 00586 + 20 /* max int len */; 00587 contentLengthHeader = new char[contentLengthHeaderSize]; 00588 sprintf(contentLengthHeader, contentLengthHeaderFmt, contentStrLen); 00589 contentLengthHeaderWasAllocated = True; 00590 } 00591 00592 if (strcmp(request->commandName(), "DESCRIBE") == 0) { 00593 extraHeaders = (char*)"Accept: application/sdp\r\n"; 00594 } else if (strcmp(request->commandName(), "OPTIONS") == 0) { 00595 } else if (strcmp(request->commandName(), "ANNOUNCE") == 0) { 00596 extraHeaders = (char*)"Content-Type: application/sdp\r\n"; 00597 } else if (strcmp(request->commandName(), "SETUP") == 0) { 00598 MediaSubsession& subsession = *request->subsession(); 00599 Boolean streamUsingTCP = (request->booleanFlags()&0x1) != 0; 00600 Boolean streamOutgoing = (request->booleanFlags()&0x2) != 0; 00601 Boolean forceMulticastOnUnspecified = (request->booleanFlags()&0x4) != 0; 00602 00603 char const *prefix, *separator, *suffix; 00604 constructSubsessionURL(subsession, prefix, separator, suffix); 00605 00606 char const* transportFmt; 00607 if (strcmp(subsession.protocolName(), "UDP") == 0) { 00608 suffix = ""; 00609 transportFmt = "Transport: RAW/RAW/UDP%s%s%s=%d-%d\r\n"; 00610 } else { 00611 transportFmt = "Transport: RTP/AVP%s%s%s=%d-%d\r\n"; 00612 } 00613 00614 cmdURL = new char[strlen(prefix) + strlen(separator) + strlen(suffix) + 1]; 00615 cmdURLWasAllocated = True; 00616 sprintf(cmdURL, "%s%s%s", prefix, separator, suffix); 00617 00618 // Construct a "Transport:" header. 00619 char const* transportTypeStr; 00620 char const* modeStr = streamOutgoing ? ";mode=receive" : ""; 00621 // Note: I think the above is nonstandard, but DSS wants it this way 00622 char const* portTypeStr; 00623 portNumBits rtpNumber, rtcpNumber; 00624 if (streamUsingTCP) { // streaming over the RTSP connection 00625 transportTypeStr = "/TCP;unicast"; 00626 portTypeStr = ";interleaved"; 00627 rtpNumber = fTCPStreamIdCount++; 00628 rtcpNumber = fTCPStreamIdCount++; 00629 } else { // normal RTP streaming 00630 unsigned connectionAddress = subsession.connectionEndpointAddress(); 00631 Boolean requestMulticastStreaming 00632 = IsMulticastAddress(connectionAddress) || (connectionAddress == 0 && forceMulticastOnUnspecified); 00633 transportTypeStr = requestMulticastStreaming ? ";multicast" : ";unicast"; 00634 portTypeStr = ";client_port"; 00635 rtpNumber = subsession.clientPortNum(); 00636 if (rtpNumber == 0) { 00637 envir().setResultMsg("Client port number unknown\n"); 00638 delete[] cmdURL; 00639 break; 00640 } 00641 rtcpNumber = rtpNumber + 1; 00642 } 00643 unsigned transportSize = strlen(transportFmt) 00644 + strlen(transportTypeStr) + strlen(modeStr) + strlen(portTypeStr) + 2*5 /* max port len */; 00645 char* transportStr = new char[transportSize]; 00646 sprintf(transportStr, transportFmt, 00647 transportTypeStr, modeStr, portTypeStr, rtpNumber, rtcpNumber); 00648 00649 // When sending more than one "SETUP" request, include a "Session:" header in the 2nd and later commands: 00650 char* sessionStr = createSessionString(fLastSessionId); 00651 00652 // The "Transport:" and "Session:" (if present) headers make up the 'extra headers': 00653 extraHeaders = new char[transportSize + strlen(sessionStr)]; 00654 extraHeadersWereAllocated = True; 00655 sprintf(extraHeaders, "%s%s", transportStr, sessionStr); 00656 delete[] transportStr; delete[] sessionStr; 00657 } else if (strcmp(request->commandName(), "GET") == 0 || strcmp(request->commandName(), "POST") == 0) { 00658 // We will be sending a HTTP (not a RTSP) request. 00659 // Begin by re-parsing our RTSP URL, just to get the stream name, which we'll use as our 'cmdURL' in the subsequent request: 00660 char* username; 00661 char* password; 00662 NetAddress destAddress; 00663 portNumBits urlPortNum; 00664 if (!parseRTSPURL(envir(), fBaseURL, username, password, destAddress, urlPortNum, (char const**)&cmdURL)) break; 00665 if (cmdURL[0] == '\0') cmdURL = (char*)"/"; 00666 delete[] username; 00667 delete[] password; 00668 00669 protocolStr = "HTTP/1.0"; 00670 00671 if (strcmp(request->commandName(), "GET") == 0) { 00672 // Create a 'session cookie' string, using MD5: 00673 struct { 00674 struct timeval timestamp; 00675 unsigned counter; 00676 } seedData; 00677 gettimeofday(&seedData.timestamp, NULL); 00678 seedData.counter = ++fSessionCookieCounter; 00679 our_MD5Data((unsigned char*)(&seedData), sizeof seedData, fSessionCookie); 00680 // DSS seems to require that the 'session cookie' string be 22 bytes long: 00681 fSessionCookie[23] = '\0'; 00682 00683 char const* const extraHeadersFmt = 00684 "x-sessioncookie: %s\r\n" 00685 "Accept: application/x-rtsp-tunnelled\r\n" 00686 "Pragma: no-cache\r\n" 00687 "Cache-Control: no-cache\r\n"; 00688 unsigned extraHeadersSize = strlen(extraHeadersFmt) 00689 + strlen(fSessionCookie); 00690 extraHeaders = new char[extraHeadersSize]; 00691 extraHeadersWereAllocated = True; 00692 sprintf(extraHeaders, extraHeadersFmt, 00693 fSessionCookie); 00694 } else { // "POST" 00695 char const* const extraHeadersFmt = 00696 "x-sessioncookie: %s\r\n" 00697 "Content-Type: application/x-rtsp-tunnelled\r\n" 00698 "Pragma: no-cache\r\n" 00699 "Cache-Control: no-cache\r\n" 00700 "Content-Length: 32767\r\n" 00701 "Expires: Sun, 9 Jan 1972 00:00:00 GMT\r\n"; 00702 unsigned extraHeadersSize = strlen(extraHeadersFmt) 00703 + strlen(fSessionCookie); 00704 extraHeaders = new char[extraHeadersSize]; 00705 extraHeadersWereAllocated = True; 00706 sprintf(extraHeaders, extraHeadersFmt, 00707 fSessionCookie); 00708 } 00709 } else { // "PLAY", "PAUSE", "TEARDOWN", "RECORD", "SET_PARAMETER", "GET_PARAMETER" 00710 // First, make sure that we have a RTSP session in progress 00711 if (fLastSessionId == NULL) { 00712 envir().setResultMsg("No RTSP session is currently in progress\n"); 00713 break; 00714 } 00715 00716 char const* sessionId; 00717 float originalScale; 00718 if (request->session() != NULL) { 00719 // Session-level operation 00720 cmdURL = (char*)sessionURL(*request->session()); 00721 00722 sessionId = fLastSessionId; 00723 originalScale = request->session()->scale(); 00724 } else { 00725 // Media-level operation 00726 char const *prefix, *separator, *suffix; 00727 constructSubsessionURL(*request->subsession(), prefix, separator, suffix); 00728 cmdURL = new char[strlen(prefix) + strlen(separator) + strlen(suffix) + 1]; 00729 cmdURLWasAllocated = True; 00730 sprintf(cmdURL, "%s%s%s", prefix, separator, suffix); 00731 00732 sessionId = request->subsession()->sessionId(); 00733 originalScale = request->subsession()->scale(); 00734 } 00735 00736 if (strcmp(request->commandName(), "PLAY") == 0) { 00737 // Create "Session:", "Scale:", and "Range:" headers; these make up the 'extra headers': 00738 char* sessionStr = createSessionString(sessionId); 00739 char* scaleStr = createScaleString(request->scale(), originalScale); 00740 char* rangeStr = createRangeString(request->start(), request->end(), request->absStartTime(), request->absEndTime()); 00741 extraHeaders = new char[strlen(sessionStr) + strlen(scaleStr) + strlen(rangeStr) + 1]; 00742 extraHeadersWereAllocated = True; 00743 sprintf(extraHeaders, "%s%s%s", sessionStr, scaleStr, rangeStr); 00744 delete[] sessionStr; delete[] scaleStr; delete[] rangeStr; 00745 } else { 00746 // Create a "Session:" header; this makes up our 'extra headers': 00747 extraHeaders = createSessionString(sessionId); 00748 extraHeadersWereAllocated = True; 00749 } 00750 } 00751 00752 char* authenticatorStr = createAuthenticatorString(request->commandName(), fBaseURL); 00753 00754 char const* const cmdFmt = 00755 "%s %s %s\r\n" 00756 "CSeq: %d\r\n" 00757 "%s" 00758 "%s" 00759 "%s" 00760 "%s" 00761 "\r\n" 00762 "%s"; 00763 unsigned cmdSize = strlen(cmdFmt) 00764 + strlen(request->commandName()) + strlen(cmdURL) + strlen(protocolStr) 00765 + 20 /* max int len */ 00766 + strlen(authenticatorStr) 00767 + fUserAgentHeaderStrLen 00768 + strlen(extraHeaders) 00769 + strlen(contentLengthHeader) 00770 + contentStrLen; 00771 cmd = new char[cmdSize]; 00772 sprintf(cmd, cmdFmt, 00773 request->commandName(), cmdURL, protocolStr, 00774 request->cseq(), 00775 authenticatorStr, 00776 fUserAgentHeaderStr, 00777 extraHeaders, 00778 contentLengthHeader, 00779 contentStr); 00780 delete[] authenticatorStr; 00781 if (cmdURLWasAllocated) delete[] cmdURL; 00782 if (extraHeadersWereAllocated) delete[] extraHeaders; 00783 if (contentLengthHeaderWasAllocated) delete[] contentLengthHeader; 00784 00785 if (fVerbosityLevel >= 1) envir() << "Sending request: " << cmd << "\n"; 00786 00787 if (fTunnelOverHTTPPortNum != 0 && strcmp(request->commandName(), "GET") != 0 && strcmp(request->commandName(), "POST") != 0) { 00788 // When we're tunneling RTSP-over-HTTP, we Base-64-encode the request before we send it. 00789 // (However, we don't do this for the HTTP "GET" and "POST" commands that we use to set up the tunnel.) 00790 char* origCmd = cmd; 00791 cmd = base64Encode(origCmd, strlen(cmd)); 00792 if (fVerbosityLevel >= 1) envir() << "\tThe request was base-64 encoded to: " << cmd << "\n\n"; 00793 delete[] origCmd; 00794 } 00795 00796 if (send(fOutputSocketNum, cmd, strlen(cmd), 0) < 0) { 00797 char const* errFmt = "%s send() failed: "; 00798 unsigned const errLength = strlen(errFmt) + strlen(request->commandName()); 00799 char* err = new char[errLength]; 00800 sprintf(err, errFmt, request->commandName()); 00801 envir().setResultErrMsg(err); 00802 delete[] err; 00803 break; 00804 } 00805 00806 // The command send succeeded, so enqueue the request record, so that its response (when it comes) can be handled. 00807 // However, note that we do not expect a response to a POST command with RTSP-over-HTTP, so don't enqueue that. 00808 int cseq = request->cseq(); 00809 00810 if (fTunnelOverHTTPPortNum == 0 || strcmp(request->commandName(), "POST") != 0) { 00811 fRequestsAwaitingResponse.enqueue(request); 00812 } else { 00813 delete request; 00814 } 00815 00816 delete[] cmd; 00817 return cseq; 00818 } while (0); 00819 00820 // An error occurred, so call the response handler immediately (indicating the error): 00821 delete[] cmd; 00822 handleRequestError(request); 00823 delete request; 00824 return 0; 00825 }
| Boolean RTSPClient::isRTSPClient | ( | ) | const [private, virtual] |
Reimplemented from Medium.
Definition at line 343 of file RTSPClient.cpp.
References True.
00343 { 00344 return True; 00345 }
| void RTSPClient::resetTCPSockets | ( | ) | [private] |
Definition at line 359 of file RTSPClient.cpp.
References closeSocket, TaskScheduler::disableBackgroundHandling(), Medium::envir(), fInputSocketNum, fOutputSocketNum, and UsageEnvironment::taskScheduler().
Referenced by connectionHandler1(), handleResponseBytes(), openConnection(), reset(), and responseHandlerForHTTP_GET1().
00359 { 00360 if (fInputSocketNum >= 0) { 00361 envir().taskScheduler().disableBackgroundHandling(fInputSocketNum); 00362 ::closeSocket(fInputSocketNum); 00363 if (fOutputSocketNum != fInputSocketNum) { 00364 envir().taskScheduler().disableBackgroundHandling(fOutputSocketNum); 00365 ::closeSocket(fOutputSocketNum); 00366 } 00367 } 00368 fInputSocketNum = fOutputSocketNum = -1; 00369 }
| void RTSPClient::resetResponseBuffer | ( | ) | [private] |
Definition at line 371 of file RTSPClient.cpp.
References fResponseBufferBytesLeft, fResponseBytesAlreadySeen, and responseBufferSize.
Referenced by handleResponseBytes(), reset(), and RTSPClient().
00371 { 00372 fResponseBytesAlreadySeen = 0; 00373 fResponseBufferBytesLeft = responseBufferSize; 00374 }
| int RTSPClient::openConnection | ( | ) | [private] |
Definition at line 380 of file RTSPClient.cpp.
References connectToServer(), NetAddress::data(), Medium::envir(), fBaseURL, fCurrentAuthenticator, fInputSocketNum, fOutputSocketNum, fServerAddress, fTunnelOverHTTPPortNum, ignoreSigPipeOnSocket(), incomingDataHandler(), NULL, parseRTSPURL(), password, resetTCPSockets(), TaskScheduler::setBackgroundHandling(), setupStreamSocket(), Authenticator::setUsernameAndPassword(), SOCKET_EXCEPTION, SOCKET_READABLE, UsageEnvironment::taskScheduler(), and username.
Referenced by sendRequest().
00380 { 00381 do { 00382 // Set up a connection to the server. Begin by parsing the URL: 00383 00384 char* username; 00385 char* password; 00386 NetAddress destAddress; 00387 portNumBits urlPortNum; 00388 char const* urlSuffix; 00389 if (!parseRTSPURL(envir(), fBaseURL, username, password, destAddress, urlPortNum, &urlSuffix)) break; 00390 portNumBits destPortNum = fTunnelOverHTTPPortNum == 0 ? urlPortNum : fTunnelOverHTTPPortNum; 00391 if (username != NULL || password != NULL) { 00392 fCurrentAuthenticator.setUsernameAndPassword(username, password); 00393 delete[] username; 00394 delete[] password; 00395 } 00396 00397 // We don't yet have a TCP socket (or we used to have one, but it got closed). Set it up now. 00398 fInputSocketNum = fOutputSocketNum = setupStreamSocket(envir(), 0); 00399 if (fInputSocketNum < 0) break; 00400 ignoreSigPipeOnSocket(fInputSocketNum); // so that servers on the same host that get killed don't also kill us 00401 00402 // Connect to the remote endpoint: 00403 fServerAddress = *(netAddressBits*)(destAddress.data()); 00404 int connectResult = connectToServer(fInputSocketNum, destPortNum); 00405 if (connectResult < 0) break; 00406 else if (connectResult > 0) { 00407 // The connection succeeded. Arrange to handle responses to requests sent on it: 00408 envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE|SOCKET_EXCEPTION, 00409 (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this); 00410 } 00411 return connectResult; 00412 } while (0); 00413 00414 resetTCPSockets(); 00415 return -1; 00416 }
| int RTSPClient::connectToServer | ( | int | socketNum, | |
| portNumBits | remotePortNum | |||
| ) | [private] |
Definition at line 418 of file RTSPClient.cpp.
References connectionHandler(), Medium::envir(), fServerAddress, fVerbosityLevel, UsageEnvironment::getErrno(), UsageEnvironment::getResultMsg(), MAKE_SOCKADDR_IN, TaskScheduler::setBackgroundHandling(), UsageEnvironment::setResultErrMsg(), SOCKET_EXCEPTION, SOCKET_WRITABLE, and UsageEnvironment::taskScheduler().
Referenced by openConnection(), and responseHandlerForHTTP_GET1().
00418 { 00419 MAKE_SOCKADDR_IN(remoteName, fServerAddress, htons(remotePortNum)); 00420 if (fVerbosityLevel >= 1) { 00421 envir() << "Opening connection to " << AddressString(remoteName).val() << ", port " << remotePortNum << "...\n"; 00422 } 00423 if (connect(socketNum, (struct sockaddr*) &remoteName, sizeof remoteName) != 0) { 00424 int const err = envir().getErrno(); 00425 if (err == EINPROGRESS || err == EWOULDBLOCK) { 00426 // The connection is pending; we'll need to handle it later. Wait for our socket to be 'writable', or have an exception. 00427 envir().taskScheduler().setBackgroundHandling(socketNum, SOCKET_WRITABLE|SOCKET_EXCEPTION, 00428 (TaskScheduler::BackgroundHandlerProc*)&connectionHandler, this); 00429 return 0; 00430 } 00431 envir().setResultErrMsg("connect() failed: "); 00432 if (fVerbosityLevel >= 1) envir() << "..." << envir().getResultMsg() << "\n"; 00433 return -1; 00434 } 00435 if (fVerbosityLevel >= 1) envir() << "...local connection opened\n"; 00436 00437 return 1; 00438 }
| char * RTSPClient::createAuthenticatorString | ( | char const * | cmd, | |
| char const * | url | |||
| ) | [private] |
Definition at line 441 of file RTSPClient.cpp.
References base64Encode(), Authenticator::computeDigestResponse(), fCurrentAuthenticator, Authenticator::nonce(), NULL, Authenticator::password(), Authenticator::realm(), Authenticator::reclaimDigestResponse(), strDup(), and Authenticator::username().
Referenced by sendRequest().
00441 { 00442 Authenticator& auth = fCurrentAuthenticator; // alias, for brevity 00443 if (auth.realm() != NULL && auth.username() != NULL && auth.password() != NULL) { 00444 // We have a filled-in authenticator, so use it: 00445 char* authenticatorStr; 00446 if (auth.nonce() != NULL) { // Digest authentication 00447 char const* const authFmt = 00448 "Authorization: Digest username=\"%s\", realm=\"%s\", " 00449 "nonce=\"%s\", uri=\"%s\", response=\"%s\"\r\n"; 00450 char const* response = auth.computeDigestResponse(cmd, url); 00451 unsigned authBufSize = strlen(authFmt) 00452 + strlen(auth.username()) + strlen(auth.realm()) 00453 + strlen(auth.nonce()) + strlen(url) + strlen(response); 00454 authenticatorStr = new char[authBufSize]; 00455 sprintf(authenticatorStr, authFmt, 00456 auth.username(), auth.realm(), 00457 auth.nonce(), url, response); 00458 auth.reclaimDigestResponse(response); 00459 } else { // Basic authentication 00460 char const* const authFmt = "Authorization: Basic %s\r\n"; 00461 00462 unsigned usernamePasswordLength = strlen(auth.username()) + 1 + strlen(auth.password()); 00463 char* usernamePassword = new char[usernamePasswordLength+1]; 00464 sprintf(usernamePassword, "%s:%s", auth.username(), auth.password()); 00465 00466 char* response = base64Encode(usernamePassword, usernamePasswordLength); 00467 unsigned const authBufSize = strlen(authFmt) + strlen(response) + 1; 00468 authenticatorStr = new char[authBufSize]; 00469 sprintf(authenticatorStr, authFmt, response); 00470 delete[] response; delete[] usernamePassword; 00471 } 00472 00473 return authenticatorStr; 00474 } 00475 00476 // We don't have a (filled-in) authenticator. 00477 return strDup(""); 00478 }
| void RTSPClient::handleRequestError | ( | RequestRecord * | request | ) | [private] |
Definition at line 827 of file RTSPClient.cpp.
References Medium::envir(), UsageEnvironment::getErrno(), RTSPClient::RequestRecord::handler(), NULL, and strDup().
Referenced by connectionHandler1(), handleResponseBytes(), responseHandlerForHTTP_GET1(), and sendRequest().
00827 { 00828 int resultCode = -envir().getErrno(); 00829 if (resultCode == 0) { 00830 // Choose some generic error code instead: 00831 #if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4) 00832 resultCode = -WSAENOTCONN; 00833 #else 00834 resultCode = -ENOTCONN; 00835 #endif 00836 } 00837 if (request->handler() != NULL) (*request->handler())(this, resultCode, strDup(envir().getResultMsg())); 00838 }
| Boolean RTSPClient::parseResponseCode | ( | char const * | line, | |
| unsigned & | responseCode, | |||
| char const *& | responseString | |||
| ) | [private] |
Definition at line 841 of file RTSPClient.cpp.
Referenced by handleResponseBytes().
00841 { 00842 if (sscanf(line, "RTSP/%*s%u", &responseCode) != 1 && 00843 sscanf(line, "HTTP/%*s%u", &responseCode) != 1) return False; 00844 // Note: We check for HTTP responses as well as RTSP responses, both in order to setup RTSP-over-HTTP tunneling, 00845 // and so that we get back a meaningful error if the client tried to mistakenly send a RTSP command to a HTTP-only server. 00846 00847 // Use everything after the RTSP/* (or HTTP/*) as the response string: 00848 responseString = line; 00849 while (responseString[0] != '\0' && responseString[0] != ' ' && responseString[0] != '\t') ++responseString; 00850 while (responseString[0] != '\0' && (responseString[0] == ' ' || responseString[0] == '\t')) ++responseString; // skip whitespace 00851 00852 return True; 00853 }
| void RTSPClient::handleIncomingRequest | ( | ) | [private] |
Definition at line 855 of file RTSPClient.cpp.
References Medium::envir(), fOutputSocketNum, fResponseBuffer, fResponseBytesAlreadySeen, fVerbosityLevel, parseRTSPRequestString(), and RTSP_PARAM_STRING_MAX.
Referenced by handleResponseBytes().
00855 { 00856 // Parse the request string into command name and 'CSeq', then 'handle' the command (by responding that we don't support it): 00857 char cmdName[RTSP_PARAM_STRING_MAX]; 00858 char urlPreSuffix[RTSP_PARAM_STRING_MAX]; 00859 char urlSuffix[RTSP_PARAM_STRING_MAX]; 00860 char cseq[RTSP_PARAM_STRING_MAX]; 00861 char sessionId[RTSP_PARAM_STRING_MAX]; 00862 unsigned contentLength; 00863 if (!parseRTSPRequestString(fResponseBuffer, fResponseBytesAlreadySeen, 00864 cmdName, sizeof cmdName, 00865 urlPreSuffix, sizeof urlPreSuffix, 00866 urlSuffix, sizeof urlSuffix, 00867 cseq, sizeof cseq, 00868 sessionId, sizeof sessionId, 00869 contentLength)) { 00870 return; 00871 } else { 00872 if (fVerbosityLevel >= 1) { 00873 envir() << "Received incoming RTSP request: " << fResponseBuffer << "\n"; 00874 } 00875 char tmpBuf[2*RTSP_PARAM_STRING_MAX]; 00876 snprintf((char*)tmpBuf, sizeof tmpBuf, 00877 "RTSP/1.0 405 Method Not Allowed\r\nCSeq: %s\r\n\r\n", cseq); 00878 send(fOutputSocketNum, tmpBuf, strlen(tmpBuf), 0); 00879 } 00880 }
| Boolean RTSPClient::checkForHeader | ( | char const * | line, | |
| char const * | headerName, | |||
| unsigned | headerNameLength, | |||
| char const *& | headerParams | |||
| ) | [static, private] |
Definition at line 882 of file RTSPClient.cpp.
References _strncasecmp, False, and True.
Referenced by handleResponseBytes().
00882 { 00883 if (_strncasecmp(line, headerName, headerNameLength) != 0) return False; 00884 00885 // The line begins with the desired header name. Trim off any whitespace, and return the header parameters: 00886 unsigned paramIndex = headerNameLength; 00887 while (line[paramIndex] != '\0' && (line[paramIndex] == ' ' || line[paramIndex] == '\t')) ++paramIndex; 00888 if (&line[paramIndex] == '\0') return False; // the header is assumed to be bad if it has no parameters 00889 00890 headerParams = &line[paramIndex]; 00891 return True; 00892 }
| Boolean RTSPClient::parseTransportParams | ( | char const * | paramsStr, | |
| char *& | serverAddressStr, | |||
| portNumBits & | serverPortNum, | |||
| unsigned char & | rtpChannelId, | |||
| unsigned char & | rtcpChannelId | |||
| ) | [private] |
Definition at line 894 of file RTSPClient.cpp.
References _strncasecmp, False, NULL, strDup(), strDupSize(), and True.
Referenced by handleSETUPResponse().
00896 { 00897 // Initialize the return parameters to 'not found' values: 00898 serverAddressStr = NULL; 00899 serverPortNum = 0; 00900 rtpChannelId = rtcpChannelId = 0xFF; 00901 if (paramsStr == NULL) return False; 00902 00903 char* foundServerAddressStr = NULL; 00904 Boolean foundServerPortNum = False; 00905 portNumBits clientPortNum = 0; 00906 Boolean foundClientPortNum = False; 00907 Boolean foundChannelIds = False; 00908 unsigned rtpCid, rtcpCid; 00909 Boolean isMulticast = True; // by default 00910 char* foundDestinationStr = NULL; 00911 portNumBits multicastPortNumRTP, multicastPortNumRTCP; 00912 Boolean foundMulticastPortNum = False; 00913 00914 // Run through each of the parameters, looking for ones that we handle: 00915 char const* fields = paramsStr; 00916 char* field = strDupSize(fields); 00917 while (sscanf(fields, "%[^;]", field) == 1) { 00918 if (sscanf(field, "server_port=%hu", &serverPortNum) == 1) { 00919 foundServerPortNum = True; 00920 } else if (sscanf(field, "client_port=%hu", &clientPortNum) == 1) { 00921 foundClientPortNum = True; 00922 } else if (_strncasecmp(field, "source=", 7) == 0) { 00923 delete[] foundServerAddressStr; 00924 foundServerAddressStr = strDup(field+7); 00925 } else if (sscanf(field, "interleaved=%u-%u", &rtpCid, &rtcpCid) == 2) { 00926 rtpChannelId = (unsigned char)rtpCid; 00927 rtcpChannelId = (unsigned char)rtcpCid; 00928 foundChannelIds = True; 00929 } else if (strcmp(field, "unicast") == 0) { 00930 isMulticast = False; 00931 } else if (_strncasecmp(field, "destination=", 12) == 0) { 00932 delete[] foundDestinationStr; 00933 foundDestinationStr = strDup(field+12); 00934 } else if (sscanf(field, "port=%hu-%hu", &multicastPortNumRTP, &multicastPortNumRTCP) == 2 || 00935 sscanf(field, "port=%hu", &multicastPortNumRTP) == 1) { 00936 foundMulticastPortNum = True; 00937 } 00938 00939 fields += strlen(field); 00940 while (fields[0] == ';') ++fields; // skip over all leading ';' chars 00941 if (fields[0] == '\0') break; 00942 } 00943 delete[] field; 00944 00945 // If we're multicast, and have a "destination=" (multicast) address, then use this 00946 // as the 'server' address (because some weird servers don't specify the multicast 00947 // address earlier, in the "DESCRIBE" response's SDP: 00948 if (isMulticast && foundDestinationStr != NULL && foundMulticastPortNum) { 00949 delete[] foundServerAddressStr; 00950 serverAddressStr = foundDestinationStr; 00951 serverPortNum = multicastPortNumRTP; 00952 return True; 00953 } 00954 delete[] foundDestinationStr; 00955 00956 // We have a valid "Transport:" header if any of the following are true: 00957 // - We saw a "interleaved=" field, indicating RTP/RTCP-over-TCP streaming, or 00958 // - We saw a "server_port=" field, or 00959 // - We saw a "client_port=" field. 00960 // If we didn't also see a "server_port=" field, then the server port is assumed to be the same as the client port. 00961 if (foundChannelIds || foundServerPortNum || foundClientPortNum) { 00962 if (foundClientPortNum && !foundServerPortNum) { 00963 serverPortNum = clientPortNum; 00964 } 00965 serverAddressStr = foundServerAddressStr; 00966 return True; 00967 } 00968 00969 delete[] foundServerAddressStr; 00970 return False; 00971 }
| Boolean RTSPClient::parseScaleParam | ( | char const * | paramStr, | |
| float & | scale | |||
| ) | [private] |
Definition at line 973 of file RTSPClient.cpp.
References Numeric.
Referenced by handlePLAYResponse().
| Boolean RTSPClient::parseRTPInfoParams | ( | char const *& | paramStr, | |
| u_int16_t & | seqNum, | |||
| u_int32_t & | timestamp | |||
| ) | [private] |
Definition at line 978 of file RTSPClient.cpp.
References False, NULL, strDupSize(), and True.
Referenced by handlePLAYResponse().
00978 { 00979 if (paramsStr == NULL || paramsStr[0] == '\0') return False; 00980 while (paramsStr[0] == ',') ++paramsStr; 00981 00982 // "paramsStr" now consists of a ';'-separated list of parameters, ending with ',' or '\0'. 00983 char* field = strDupSize(paramsStr); 00984 00985 Boolean sawSeq = False, sawRtptime = False; 00986 while (sscanf(paramsStr, "%[^;,]", field) == 1) { 00987 if (sscanf(field, "seq=%hu", &seqNum) == 1) { 00988 sawSeq = True; 00989 } else if (sscanf(field, "rtptime=%u", ×tamp) == 1) { 00990 sawRtptime = True; 00991 } 00992 00993 paramsStr += strlen(field); 00994 if (paramsStr[0] == '\0' || paramsStr[0] == ',') break; 00995 // ASSERT: paramsStr[0] == ';' 00996 ++paramsStr; // skip over the ';' 00997 } 00998 00999 delete[] field; 01000 // For the "RTP-Info:" parameters to be useful to us, we need to have seen both the "seq=" and "rtptime=" parameters: 01001 return sawSeq && sawRtptime; 01002 }
| Boolean RTSPClient::handleSETUPResponse | ( | MediaSubsession & | subsession, | |
| char const * | sessionParamsStr, | |||
| char const * | transportParamsStr, | |||
| Boolean | streamUsingTCP | |||
| ) | [private] |
Definition at line 1004 of file RTSPClient.cpp.
References MediaSubsession::connectionEndpointAddress(), MediaSubsession::connectionEndpointName(), RTPSource::enableRTCPReports(), Medium::envir(), False, fInputSocketNum, fLastSessionId, fServerAddress, fSessionTimeoutParameter, handleAlternativeRequestByte(), NULL, Groupsock::output(), parseTransportParams(), responseBufferSize, MediaSubsession::rtcpChannelId, RTCPInstance::RTCPgs(), MediaSubsession::rtcpInstance(), MediaSubsession::rtpChannelId, RTPSource::RTPgs(), MediaSubsession::rtpSource(), MediaSubsession::serverPortNum, MediaSubsession::setDestinations(), UsageEnvironment::setResultMsg(), RTPSource::setServerRequestAlternativeByteHandler(), MediaSubsession::setSessionId(), RTCPInstance::setStreamSocket(), RTPSource::setStreamSocket(), strDup(), subsession, and True.
Referenced by handleResponseBytes().
01005 { 01006 char* sessionId = new char[responseBufferSize]; // ensures we have enough space 01007 Boolean success = False; 01008 do { 01009 // Check for a session id: 01010 if (sessionParamsStr == NULL || sscanf(sessionParamsStr, "%[^;]", sessionId) != 1) { 01011 envir().setResultMsg("Missing or bad \"Session:\" header"); 01012 break; 01013 } 01014 subsession.setSessionId(sessionId); 01015 delete[] fLastSessionId; fLastSessionId = strDup(sessionId); 01016 01017 // Also look for an optional "; timeout = " parameter following this: 01018 char const* afterSessionId = sessionParamsStr + strlen(sessionId); 01019 int timeoutVal; 01020 if (sscanf(afterSessionId, "; timeout = %d", &timeoutVal) == 1) { 01021 fSessionTimeoutParameter = timeoutVal; 01022 } 01023 01024 // Parse the "Transport:" header parameters: 01025 char* serverAddressStr; 01026 portNumBits serverPortNum; 01027 unsigned char rtpChannelId, rtcpChannelId; 01028 if (!parseTransportParams(transportParamsStr, serverAddressStr, serverPortNum, rtpChannelId, rtcpChannelId)) { 01029 envir().setResultMsg("Missing or bad \"Transport:\" header"); 01030 break; 01031 } 01032 delete[] subsession.connectionEndpointName(); 01033 subsession.connectionEndpointName() = serverAddressStr; 01034 subsession.serverPortNum = serverPortNum; 01035 subsession.rtpChannelId = rtpChannelId; 01036 subsession.rtcpChannelId = rtcpChannelId; 01037 01038 if (streamUsingTCP) { 01039 // Tell the subsession to receive RTP (and send/receive RTCP) over the RTSP stream: 01040 if (subsession.rtpSource() != NULL) { 01041 subsession.rtpSource()->setStreamSocket(fInputSocketNum, subsession.rtpChannelId); 01042 subsession.rtpSource()->setServerRequestAlternativeByteHandler(fInputSocketNum, handleAlternativeRequestByte, this); 01043 subsession.rtpSource()->enableRTCPReports() = False; 01044 // To avoid confusing the server (which won't start handling RTP/RTCP-over-TCP until "PLAY"), don't send RTCP "RR"s yet 01045 } 01046 if (subsession.rtcpInstance() != NULL) subsession.rtcpInstance()->setStreamSocket(fInputSocketNum, subsession.rtcpChannelId); 01047 } else { 01048 // Normal case. 01049 // Set the RTP and RTCP sockets' destination address and port from the information in the SETUP response (if present): 01050 netAddressBits destAddress = subsession.connectionEndpointAddress(); 01051 if (destAddress == 0) destAddress = fServerAddress; 01052 subsession.setDestinations(destAddress); 01053 01054 // Hack: To increase the likelihood of UDP packets from the server reaching us, if we're behind a NAT, send a few 'dummy' 01055 // UDP packets to the server now. (We do this on both our RTP port and our RTCP port.) 01056 Groupsock* gs1 = NULL; Groupsock* gs2 = NULL; 01057 if (subsession.rtpSource() != NULL) gs1 = subsession.rtpSource()->RTPgs(); 01058 if (subsession.rtcpInstance() != NULL) gs2 = subsession.rtcpInstance()->RTCPgs(); 01059 u_int32_t const dummy = 0xFEEDFACE; 01060 unsigned const numDummyPackets = 2; 01061 for (unsigned i = 0; i < numDummyPackets; ++i) { 01062 if (gs1 != NULL) gs1->output(envir(), 255, (unsigned char*)&dummy, sizeof dummy); 01063 if (gs2 != NULL) gs2->output(envir(), 255, (unsigned char*)&dummy, sizeof dummy); 01064 } 01065 } 01066 01067 success = True; 01068 } while (0); 01069 01070 delete[] sessionId; 01071 return success; 01072 }
| Boolean RTSPClient::handlePLAYResponse | ( | MediaSession & | session, | |
| MediaSubsession & | subsession, | |||
| char const * | scaleParamsStr, | |||
| char const * | rangeParamsStr, | |||
| char const * | rtpInfoParamsStr | |||
| ) | [private] |
Definition at line 1074 of file RTSPClient.cpp.
References MediaSubsession::_absEndTime(), MediaSession::_absEndTime(), MediaSubsession::_absStartTime(), MediaSession::_absStartTime(), MediaSubsession::_playEndTime(), MediaSubsession::_playStartTime(), RTPSource::enableRTCPReports(), Medium::envir(), False, MediaSubsession::infoIsNew, iter, MediaSubsessionIterator::next(), NULL, parseRangeParam(), parseRTPInfoParams(), parseScaleParam(), MediaSession::playEndTime(), MediaSession::playStartTime(), MediaSubsession::rtpInfo, MediaSubsession::rtpSource(), MediaSubsession::scale(), MediaSession::scale(), MediaSubsession::seqNum, session, UsageEnvironment::setResultMsg(), subsession, MediaSubsession::timestamp, and True.
Referenced by handleResponseBytes().
01075 { 01076 Boolean scaleOK = False, rangeOK = False; 01077 do { 01078 if (&session != NULL) { 01079 // The command was on the whole session 01080 if (scaleParamsStr != NULL && !parseScaleParam(scaleParamsStr, session.scale())) break; 01081 scaleOK = True; 01082 if (rangeParamsStr != NULL && !parseRangeParam(rangeParamsStr, session.playStartTime(), session.playEndTime(), 01083 session._absStartTime(), session._absEndTime())) break; 01084 rangeOK = True; 01085 01086 MediaSubsessionIterator iter(session); 01087 MediaSubsession* subsession; 01088 while ((subsession = iter.next()) != NULL) { 01089 u_int16_t seqNum; u_int32_t timestamp; 01090 subsession->rtpInfo.infoIsNew = False; 01091 if (parseRTPInfoParams(rtpInfoParamsStr, seqNum, timestamp)) { 01092 subsession->rtpInfo.seqNum = seqNum; 01093 subsession->rtpInfo.timestamp = timestamp; 01094 subsession->rtpInfo.infoIsNew = True; 01095 } 01096 01097 if (subsession->rtpSource() != NULL) subsession->rtpSource()->enableRTCPReports() = True; // start sending RTCP "RR"s now 01098 } 01099 } else { 01100 // The command was on a subsession 01101 if (scaleParamsStr != NULL && !parseScaleParam(scaleParamsStr, subsession.scale())) break; 01102 scaleOK = True; 01103 if (rangeParamsStr != NULL && !parseRangeParam(rangeParamsStr, subsession._playStartTime(), subsession._playEndTime(), 01104 subsession._absStartTime(), subsession._absEndTime())) break; 01105 rangeOK = True; 01106 01107 u_int16_t seqNum; u_int32_t timestamp; 01108 subsession.rtpInfo.infoIsNew = False; 01109 if (parseRTPInfoParams(rtpInfoParamsStr, seqNum, timestamp)) { 01110 subsession.rtpInfo.seqNum = seqNum; 01111 subsession.rtpInfo.timestamp = timestamp; 01112 subsession.rtpInfo.infoIsNew = True; 01113 } 01114 01115 if (subsession.rtpSource() != NULL) subsession.rtpSource()->enableRTCPReports() = True; // start sending RTCP "RR"s now 01116 } 01117 01118 return True; 01119 } while (0); 01120 01121 // An error occurred: 01122 if (!scaleOK) { 01123 envir().setResultMsg("Bad \"Scale:\" header"); 01124 } else if (!rangeOK) { 01125 envir().setResultMsg("Bad \"Range:\" header"); 01126 } else { 01127 envir().setResultMsg("Bad \"RTP-Info:\" header"); 01128 } 01129 return False; 01130 }
| Boolean RTSPClient::handleTEARDOWNResponse | ( | MediaSession & | session, | |
| MediaSubsession & | subsession | |||
| ) | [private] |
Definition at line 1132 of file RTSPClient.cpp.
References True.
Referenced by handleResponseBytes().
01132 { 01133 // Because we don't expect to always get a response to "TEARDOWN", we don't need to do anything if we do get one: 01134 return True; 01135 }
| Boolean RTSPClient::handleGET_PARAMETERResponse | ( | char const * | parameterName, | |
| char *& | resultValueString | |||
| ) | [private] |
Definition at line 1137 of file RTSPClient.cpp.
References _strncasecmp, Medium::envir(), False, NULL, UsageEnvironment::setResultMsg(), and True.
Referenced by handleResponseBytes().
01137 { 01138 do { 01139 // If "parameterName" is non-empty, it may be (possibly followed by ':' and whitespace) at the start of the result string: 01140 if (parameterName != NULL && parameterName[0] != '\0') { 01141 if (parameterName[1] == '\0') break; // sanity check; there should have been \r\n at the end of "parameterName" 01142 01143 unsigned parameterNameLen = strlen(parameterName); 01144 // ASSERT: parameterNameLen >= 2; 01145 parameterNameLen -= 2; // because of the trailing \r\n 01146 if (_strncasecmp(resultValueString, parameterName, parameterNameLen) == 0) { 01147 resultValueString += parameterNameLen; 01148 if (resultValueString[0] == ':') ++resultValueString; 01149 while (resultValueString[0] == ' ' || resultValueString[0] == '\t') ++resultValueString; 01150 } 01151 } 01152 01153 // The rest of "resultValueStr" should be our desired result, but first trim off any \r and/or \n characters at the end: 01154 unsigned resultLen = strlen(resultValueString); 01155 while (resultLen > 0 && (resultValueString[resultLen-1] == '\r' || resultValueString[resultLen-1] == '\n')) --resultLen; 01156 resultValueString[resultLen] = '\0'; 01157 01158 return True; 01159 } while (0); 01160 01161 // An error occurred: 01162 envir().setResultMsg("Bad \"GET_PARAMETER\" response"); 01163 return False; 01164 }
| Boolean RTSPClient::handleAuthenticationFailure | ( | char const * | wwwAuthenticateParamsStr | ) | [private] |
Definition at line 1166 of file RTSPClient.cpp.
References False, fCurrentAuthenticator, NULL, Authenticator::password(), Authenticator::realm(), Authenticator::setRealmAndNonce(), strDupSize(), True, and Authenticator::username().
Referenced by handleResponseBytes().
01166 { 01167 if (paramsStr == NULL) return False; // There was no "WWW-Authenticate:" header; we can't proceed. 01168 01169 // Fill in "fCurrentAuthenticator" with the information from the "WWW-Authenticate:" header: 01170 Boolean alreadyHadRealm = fCurrentAuthenticator.realm() != NULL; 01171 char* realm = strDupSize(paramsStr); 01172 char* nonce = strDupSize(paramsStr); 01173 Boolean success = True; 01174 if (sscanf(paramsStr, "Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"", realm, nonce) == 2) { 01175 fCurrentAuthenticator.setRealmAndNonce(realm, nonce); 01176 } else if (sscanf(paramsStr, "Basic realm=\"%[^\"]\"", realm) == 1) { 01177 fCurrentAuthenticator.setRealmAndNonce(realm, NULL); // Basic authentication 01178 } else { 01179 success = False; // bad "WWW-Authenticate:" header 01180 } 01181 delete[] realm; delete[] nonce; 01182 01183 if (alreadyHadRealm || fCurrentAuthenticator.username() == NULL || fCurrentAuthenticator.password() == NULL) { 01184 // We already had a 'realm', or don't have a username and/or password, 01185 // so the new "WWW-Authenticate:" header information won't help us. We remain unauthenticated. 01186 success = False; 01187 } 01188 01189 return success; 01190 }
| Boolean RTSPClient::resendCommand | ( | RequestRecord * | request | ) | [private] |
Definition at line 1192 of file RTSPClient.cpp.
References RTSPClient::RequestRecord::commandName(), RTSPClient::RequestRecord::cseq(), Medium::envir(), fCSeq, fVerbosityLevel, NULL, and sendRequest().
Referenced by handleResponseBytes().
01192 { 01193 if (fVerbosityLevel >= 1) envir() << "Resending...\n"; 01194 if (request != NULL && strcmp(request->commandName(), "GET") != 0) request->cseq() = ++fCSeq; 01195 return sendRequest(request) != 0; 01196 }
| char const * RTSPClient::sessionURL | ( | MediaSession const & | session | ) | const [private] |
Definition at line 1198 of file RTSPClient.cpp.
References MediaSession::controlPath(), fBaseURL, NULL, session, and url().
Referenced by constructSubsessionURL(), and sendRequest().
01198 { 01199 char const* url = session.controlPath(); 01200 if (url == NULL || strcmp(url, "*") == 0) url = fBaseURL; 01201 01202 return url; 01203 }
| void RTSPClient::handleAlternativeRequestByte | ( | void * | , | |
| u_int8_t | requestByte | |||
| ) | [static, private] |
Definition at line 1205 of file RTSPClient.cpp.
Referenced by handleSETUPResponse().
01205 { 01206 ((RTSPClient*)rtspClient)->handleAlternativeRequestByte1(requestByte); 01207 }
| void RTSPClient::handleAlternativeRequestByte1 | ( | u_int8_t | requestByte | ) | [private] |
Definition at line 1209 of file RTSPClient.cpp.
References Medium::envir(), fInputSocketNum, fResponseBuffer, fResponseBytesAlreadySeen, handleResponseBytes(), incomingDataHandler(), TaskScheduler::setBackgroundHandling(), SOCKET_EXCEPTION, SOCKET_READABLE, and UsageEnvironment::taskScheduler().
01209 { 01210 if (requestByte == 0xFF) { 01211 // Hack: The new handler of the input TCP socket encountered an error reading it. Indicate this: 01212 handleResponseBytes(-1); 01213 } else if (requestByte == 0xFE) { 01214 // Another hack: The new handler of the input TCP socket no longer needs it, so take back control: 01215 envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE|SOCKET_EXCEPTION, 01216 (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this); 01217 } else { 01218 // Normal case: 01219 fResponseBuffer[fResponseBytesAlreadySeen] = requestByte; 01220 handleResponseBytes(1); 01221 } 01222 }
| void RTSPClient::constructSubsessionURL | ( | MediaSubsession const & | subsession, | |
| char const *& | prefix, | |||
| char const *& | separator, | |||
| char const *& | suffix | |||
| ) | [private] |
Definition at line 1235 of file RTSPClient.cpp.
References MediaSubsession::controlPath(), isAbsoluteURL(), NULL, MediaSubsession::parentSession(), sessionURL(), and subsession.
Referenced by sendRequest().
01238 { 01239 // Figure out what the URL describing "subsession" will look like. 01240 // The URL is returned in three parts: prefix; separator; suffix 01241 //##### NOTE: This code doesn't really do the right thing if "sessionURL()" 01242 // doesn't end with a "/", and "subsession.controlPath()" is relative. 01243 // The right thing would have been to truncate "sessionURL()" back to the 01244 // rightmost "/", and then add "subsession.controlPath()". 01245 // In practice, though, each "DESCRIBE" response typically contains 01246 // a "Content-Base:" header that consists of "sessionURL()" followed by 01247 // a "/", in which case this code ends up giving the correct result. 01248 // However, we should really fix this code to do the right thing, and 01249 // also check for and use the "Content-Base:" header appropriately. ##### 01250 prefix = sessionURL(subsession.parentSession()); 01251 if (prefix == NULL) prefix = ""; 01252 01253 suffix = subsession.controlPath(); 01254 if (suffix == NULL) suffix = ""; 01255 01256 if (isAbsoluteURL(suffix)) { 01257 prefix = separator = ""; 01258 } else { 01259 unsigned prefixLen = strlen(prefix); 01260 separator = (prefixLen == 0 || prefix[prefixLen-1] == '/' || suffix[0] == '/') ? "" : "/"; 01261 } 01262 }
| Boolean RTSPClient::setupHTTPTunneling1 | ( | ) | [private] |
Definition at line 1264 of file RTSPClient.cpp.
References Medium::envir(), fTunnelOverHTTPPortNum, fVerbosityLevel, responseHandlerForHTTP_GET(), and sendRequest().
Referenced by sendRequest().
01264 { 01265 // Set up RTSP-over-HTTP tunneling, as described in 01266 // http://developer.apple.com/quicktime/icefloe/dispatch028.html and http://images.apple.com/br/quicktime/pdf/QTSS_Modules.pdf 01267 if (fVerbosityLevel >= 1) { 01268 envir() << "Requesting RTSP-over-HTTP tunneling (on port " << fTunnelOverHTTPPortNum << ")\n\n"; 01269 } 01270 01271 // Begin by sending a HTTP "GET", to set up the server->client link. Continue when we handle the response: 01272 return sendRequest(new RequestRecord(1, "GET", responseHandlerForHTTP_GET)) != 0; 01273 }
| void RTSPClient::responseHandlerForHTTP_GET | ( | RTSPClient * | rtspClient, | |
| int | responseCode, | |||
| char * | responseString | |||
| ) | [static, private] |
Definition at line 1275 of file RTSPClient.cpp.
References NULL, and responseHandlerForHTTP_GET1().
Referenced by setupHTTPTunneling1().
01275 { 01276 if (rtspClient != NULL) rtspClient->responseHandlerForHTTP_GET1(responseCode, responseString); 01277 }
| void RTSPClient::responseHandlerForHTTP_GET1 | ( | int | responseCode, | |
| char * | responseString | |||
| ) | [private] |
Definition at line 1279 of file RTSPClient.cpp.
References connectToServer(), RTSPClient::RequestQueue::dequeue(), RTSPClient::RequestQueue::enqueue(), Medium::envir(), False, fHTTPTunnelingConnectionIsPending, fOutputSocketNum, fRequestsAwaitingConnection, fRequestsAwaitingHTTPTunneling, fTunnelOverHTTPPortNum, handleRequestError(), ignoreSigPipeOnSocket(), NULL, resetTCPSockets(), sendRequest(), setupHTTPTunneling2(), setupStreamSocket(), and True.
Referenced by responseHandlerForHTTP_GET().
01279 { 01280 RequestRecord* request; 01281 do { 01282 if (responseCode != 0) break; // The HTTP "GET" failed. 01283 01284 // Having successfully set up (using the HTTP "GET" command) the server->client link, set up a second TCP connection 01285 // (to the same server & port as before) for the client->server link. All future output will be to this new socket. 01286 fOutputSocketNum = setupStreamSocket(envir(), 0); 01287 if (fOutputSocketNum < 0) break; 01288 ignoreSigPipeOnSocket(fOutputSocketNum); // so that servers on the same host that killed don't also kill us 01289 01290 fHTTPTunnelingConnectionIsPending = True; 01291 int connectResult = connectToServer(fOutputSocketNum, fTunnelOverHTTPPortNum); 01292 if (connectResult < 0) break; // an error occurred 01293 else if (connectResult == 0) { 01294 // A connection is pending. Continue setting up RTSP-over-HTTP when the connection completes. 01295 // First, move the pending requests to the 'awaiting connection' queue: 01296 while ((request = fRequestsAwaitingHTTPTunneling.dequeue()) != NULL) { 01297 fRequestsAwaitingConnection.enqueue(request); 01298 } 01299 return; 01300 } 01301 01302 // The connection succeeded. Continue setting up RTSP-over-HTTP: 01303 if (!setupHTTPTunneling2()) break; 01304 01305 // RTSP-over-HTTP tunneling succeeded. Resume the pending request(s): 01306 while ((request = fRequestsAwaitingHTTPTunneling.dequeue()) != NULL) { 01307 sendRequest(request); 01308 } 01309 return; 01310 } while (0); 01311 01312 // An error occurred. Dequeue the pending request(s), and tell them about the error: 01313 fHTTPTunnelingConnectionIsPending = False; 01314 resetTCPSockets(); // do this now, in case an error handler deletes "this" 01315 RequestQueue requestQueue(fRequestsAwaitingHTTPTunneling); 01316 while ((request = requestQueue.dequeue()) != NULL) { 01317 handleRequestError(request); 01318 delete request; 01319 } 01320 }
| Boolean RTSPClient::setupHTTPTunneling2 | ( | ) | [private] |
Definition at line 1322 of file RTSPClient.cpp.
References False, fHTTPTunnelingConnectionIsPending, NULL, and sendRequest().
Referenced by connectionHandler1(), and responseHandlerForHTTP_GET1().
01322 { 01323 fHTTPTunnelingConnectionIsPending = False; 01324 01325 // Send a HTTP "POST", to set up the client->server link. (Note that we won't see a reply to the "POST".) 01326 return sendRequest(new RequestRecord(1, "POST", NULL)) != 0; 01327 }
| void RTSPClient::connectionHandler | ( | void * | , | |
| int | ||||
| ) | [static, private] |
Definition at line 1329 of file RTSPClient.cpp.
References connectionHandler1().
Referenced by connectToServer().
01329 { 01330 RTSPClient* client = (RTSPClient*)instance; 01331 client->connectionHandler1(); 01332 }
| void RTSPClient::connectionHandler1 | ( | ) | [private] |
Definition at line 1334 of file RTSPClient.cpp.
References RTSPClient::RequestQueue::dequeue(), TaskScheduler::disableBackgroundHandling(), Medium::envir(), fHTTPTunnelingConnectionIsPending, fInputSocketNum, fOutputSocketNum, fRequestsAwaitingConnection, fVerbosityLevel, UsageEnvironment::getResultMsg(), handleRequestError(), incomingDataHandler(), NULL, resetTCPSockets(), sendRequest(), TaskScheduler::setBackgroundHandling(), UsageEnvironment::setResultErrMsg(), setupHTTPTunneling2(), SOCKET_EXCEPTION, SOCKET_READABLE, SOCKLEN_T, and UsageEnvironment::taskScheduler().
Referenced by connectionHandler().
01334 { 01335 // Restore normal handling on our sockets: 01336 envir().taskScheduler().disableBackgroundHandling(fOutputSocketNum); 01337 envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE|SOCKET_EXCEPTION, 01338 (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this); 01339 01340 // Move all requests awaiting connection into a new, temporary queue, to clear "fRequestsAwaitingConnection" 01341 // (so that "sendRequest()" doesn't get confused by "fRequestsAwaitingConnection" being nonempty, and enqueue them all over again). 01342 RequestQueue tmpRequestQueue(fRequestsAwaitingConnection); 01343 RequestRecord* request; 01344 01345 // Find out whether the connection succeeded or failed: 01346 do { 01347 int err = 0; 01348 SOCKLEN_T len = sizeof err; 01349 if (getsockopt(fInputSocketNum, SOL_SOCKET, SO_ERROR, (char*)&err, &len) < 0 || err != 0) { 01350 envir().setResultErrMsg("Connection to server failed: ", err); 01351 if (fVerbosityLevel >= 1) envir() << "..." << envir().getResultMsg() << "\n"; 01352 break; 01353 } 01354 01355 // The connection succeeded. If the connection came about from an attempt to set up RTSP-over-HTTP, finish this now: 01356 if (fVerbosityLevel >= 1) envir() << "...remote connection opened\n"; 01357 if (fHTTPTunnelingConnectionIsPending && !setupHTTPTunneling2()) break; 01358 01359 // Resume sending all pending requests: 01360 while ((request = tmpRequestQueue.dequeue()) != NULL) { 01361 sendRequest(request); 01362 } 01363 return; 01364 } while (0); 01365 01366 // An error occurred. Tell all pending requests about the error: 01367 resetTCPSockets(); // do this now, in case an error handler deletes "this" 01368 while ((request = tmpRequestQueue.dequeue()) != NULL) { 01369 handleRequestError(request); 01370 delete request; 01371 } 01372 }
| void RTSPClient::incomingDataHandler | ( | void * | , | |
| int | ||||
| ) | [static, private] |
Definition at line 1374 of file RTSPClient.cpp.
References incomingDataHandler1().
Referenced by connectionHandler1(), handleAlternativeRequestByte1(), openConnection(), and RTSPClient().
01374 { 01375 RTSPClient* client = (RTSPClient*)instance; 01376 client->incomingDataHandler1(); 01377 }
| void RTSPClient::incomingDataHandler1 | ( | ) | [private] |
Definition at line 1379 of file RTSPClient.cpp.
References Medium::envir(), fInputSocketNum, fResponseBuffer, fResponseBufferBytesLeft, fResponseBytesAlreadySeen, handleResponseBytes(), and readSocket().
Referenced by incomingDataHandler().
01379 { 01380 struct sockaddr_in dummy; // 'from' address - not used 01381 01382 int bytesRead = readSocket(envir(), fInputSocketNum, (unsigned char*)&fResponseBuffer[fResponseBytesAlreadySeen], fResponseBufferBytesLeft, dummy); 01383 handleResponseBytes(bytesRead); 01384 }
| void RTSPClient::handleResponseBytes | ( | int | newBytesRead | ) | [private] |
Definition at line 1405 of file RTSPClient.cpp.
References _strncasecmp, RTSPClient::RequestRecord::booleanFlags(), checkForHeader(), RTSPClient::RequestRecord::commandName(), RTSPClient::RequestRecord::contentStr(), RTSPClient::RequestRecord::cseq(), RTSPClient::RequestQueue::dequeue(), Medium::envir(), False, fRequestsAwaitingResponse, fResponseBuffer, fResponseBufferBytesLeft, fResponseBytesAlreadySeen, fVerbosityLevel, getLine(), handleAuthenticationFailure(), handleGET_PARAMETERResponse(), handleIncomingRequest(), handlePLAYResponse(), RTSPClient::RequestRecord::handler(), handleRequestError(), handleSETUPResponse(), handleTEARDOWNResponse(), NULL, parseResponseCode(), RTSPClient::RequestQueue::putAtHead(), resendCommand(), resetResponseBuffer(), resetTCPSockets(), responseBufferSize, RTSPClient::RequestRecord::session(), setBaseURL(), UsageEnvironment::setResultMsg(), strDup(), RTSPClient::RequestRecord::subsession(), and True.
Referenced by handleAlternativeRequestByte1(), and incomingDataHandler1().
01405 { 01406 do { 01407 if (newBytesRead >= 0 && (unsigned)newBytesRead < fResponseBufferBytesLeft) break; // data was read OK; process it below 01408 01409 if (newBytesRead >= (int)fResponseBufferBytesLeft) { 01410 // We filled up our response buffer. Treat this as an error (for the first response handler): 01411 envir().setResultMsg("RTSP response was truncated. Increase \"RTSPClient::responseBufferSize\""); 01412 } 01413 01414 // An error occurred while reading our TCP socket. Call all pending response handlers, indicating this error. 01415 // (However, the "RTSP response was truncated" error is applied to the first response handler only.) 01416 resetResponseBuffer(); 01417 RequestRecord* request; 01418 if (newBytesRead > 0) { // The "RTSP response was truncated" error 01419 if ((request = fRequestsAwaitingResponse.dequeue()) != NULL) { 01420 handleRequestError(request); 01421 delete request; 01422 } 01423 } else { 01424 RequestQueue requestQueue(fRequestsAwaitingResponse); 01425 resetTCPSockets(); // do this now, in case an error handler deletes "this" 01426 01427 while ((request = requestQueue.dequeue()) != NULL) { 01428 handleRequestError(request); 01429 delete request; 01430 } 01431 } 01432 return; 01433 } while (0); 01434 01435 fResponseBufferBytesLeft -= newBytesRead; 01436 fResponseBytesAlreadySeen += newBytesRead; 01437 fResponseBuffer[fResponseBytesAlreadySeen] = '\0'; 01438 if (fVerbosityLevel >= 1 && newBytesRead > 1) envir() << "Received " << newBytesRead << " new bytes of response data.\n"; 01439 01440 unsigned numExtraBytesAfterResponse = 0; 01441 Boolean responseSuccess = False; // by default 01442 do { 01443 // Data was read OK. Look through the data that we've read so far, to see if it contains <CR><LF><CR><LF>. 01444 // (If not, wait for more data to arrive.) 01445 Boolean endOfHeaders = False; 01446 char const* ptr = fResponseBuffer; 01447 if (fResponseBytesAlreadySeen > 3) { 01448 char const* const ptrEnd = &fResponseBuffer[fResponseBytesAlreadySeen-3]; 01449 while (ptr < ptrEnd) { 01450 if (*ptr++ == '\r' && *ptr++ == '\n' && *ptr++ == '\r' && *ptr++ == '\n') { 01451 // This is it 01452 endOfHeaders = True; 01453 break; 01454 } 01455 } 01456 } 01457 01458 if (!endOfHeaders) return; // subsequent reads will be needed to get the complete response 01459 01460 // Now that we have the complete response headers (ending with <CR><LF><CR><LF>), parse them to get the response code, CSeq, 01461 // and various other header parameters. To do this, we first make a copy of the received header data, because we'll be 01462 // modifying it by adding '\0' bytes. 01463 char* headerDataCopy; 01464 unsigned responseCode = 200; 01465 char const* responseStr = NULL; 01466 RequestRecord* foundRequest = NULL; 01467 char const* sessionParamsStr = NULL; 01468 char const* transportParamsStr = NULL; 01469 char const* scaleParamsStr = NULL; 01470 char const* rangeParamsStr = NULL; 01471 char const* rtpInfoParamsStr = NULL; 01472 char const* wwwAuthenticateParamsStr = NULL; 01473 char const* publicParamsStr = NULL; 01474 char* bodyStart = NULL; 01475 unsigned numBodyBytes = 0; 01476 responseSuccess = False; 01477 do { 01478 headerDataCopy = new char[responseBufferSize]; 01479 strncpy(headerDataCopy, fResponseBuffer, fResponseBytesAlreadySeen); 01480 headerDataCopy[fResponseBytesAlreadySeen] = '\0'; 01481 01482 char* lineStart = headerDataCopy; 01483 char* nextLineStart = getLine(lineStart); 01484 if (!parseResponseCode(lineStart, responseCode, responseStr)) { 01485 // This does not appear to be a RTSP response; perhaps it's a RTSP request instead? 01486 handleIncomingRequest(); 01487 break; // we're done with this data 01488 } 01489 01490 // Scan through the headers, handling the ones that we're interested in: 01491 Boolean reachedEndOfHeaders; 01492 unsigned cseq = 0; 01493 unsigned contentLength = 0; 01494 01495 while (1) { 01496 reachedEndOfHeaders = True; // by default; may get changed below 01497 lineStart = nextLineStart; 01498 if (lineStart == NULL) break; 01499 01500 nextLineStart = getLine(lineStart); 01501 if (lineStart[0] == '\0') break; // this is a blank line 01502 reachedEndOfHeaders = False; 01503 01504 char const* headerParamsStr; 01505 if (checkForHeader(lineStart, "CSeq:", 5, headerParamsStr)) { 01506 if (sscanf(headerParamsStr, "%u", &cseq) != 1 || cseq <= 0) { 01507 envir().setResultMsg("Bad \"CSeq:\" header: \"", lineStart, "\""); 01508 break; 01509 } 01510 // Find the handler function for "cseq": 01511 RequestRecord* request; 01512 while ((request = fRequestsAwaitingResponse.dequeue()) != NULL) { 01513 if (request->cseq() < cseq) { // assumes that the CSeq counter will never wrap around 01514 // We never received (and will never receive) a response for this handler, so delete it: 01515 if (fVerbosityLevel >= 1 && strcmp(request->commandName(), "POST") != 0) { 01516 envir() << "WARNING: The server did not respond to our \"" << request->commandName() << "\" request (CSeq: " 01517 << request->cseq() << "). The server appears to be buggy (perhaps not handling pipelined requests properly).\n"; 01518 } 01519 delete request; 01520 } else if (request->cseq() == cseq) { 01521 // This is the handler that we want. Remove its record, but remember it, so that we can later call its handler: 01522 foundRequest = request; 01523 break; 01524 } else { // request->cseq() > cseq 01525 // No handler was registered for this response, so ignore it. 01526 break; 01527 } 01528 } 01529 } else if (checkForHeader(lineStart, "Content-Length:", 15, headerParamsStr)) { 01530 if (sscanf(headerParamsStr, "%u", &contentLength) != 1) { 01531 envir().setResultMsg("Bad \"Content-Length:\" header: \"", lineStart, "\""); 01532 break; 01533 } 01534 } else if (checkForHeader(lineStart, "Content-Base:", 13, headerParamsStr)) { 01535 setBaseURL(headerParamsStr); 01536 } else if (checkForHeader(lineStart, "Session:", 8, sessionParamsStr)) { 01537 } else if (checkForHeader(lineStart, "Transport:", 10, transportParamsStr)) { 01538 } else if (checkForHeader(lineStart, "Scale:", 6, scaleParamsStr)) { 01539 } else if (checkForHeader(lineStart, "Range:", 6, rangeParamsStr)) { 01540 } else if (checkForHeader(lineStart, "RTP-Info:", 9, rtpInfoParamsStr)) { 01541 } else if (checkForHeader(lineStart, "WWW-Authenticate:", 17, headerParamsStr)) { 01542 // If we've already seen a "WWW-Authenticate:" header, then we replace it with this new one only if 01543 // the new one specifies "Digest" authentication: 01544 if (wwwAuthenticateParamsStr == NULL || _strncasecmp(headerParamsStr, "Digest", 6) == 0) { 01545 wwwAuthenticateParamsStr = headerParamsStr; 01546 } 01547 } else if (checkForHeader(lineStart, "Public:", 7, publicParamsStr)) { 01548 } else if (checkForHeader(lineStart, "Allow:", 6, publicParamsStr)) { 01549 // Note: we accept "Allow:" instead of "Public:", so that "OPTIONS" requests made to HTTP servers will work. 01550 } else if (checkForHeader(lineStart, "Location:", 9, headerParamsStr)) { 01551 setBaseURL(headerParamsStr); 01552 } 01553 } 01554 if (!reachedEndOfHeaders) break; // an error occurred 01555 01556 if (foundRequest == NULL) { 01557 // Hack: The response didn't have a "CSeq:" header; assume it's for our most recent request: 01558 foundRequest = fRequestsAwaitingResponse.dequeue(); 01559 } 01560 01561 // If we saw a "Content-Length:" header, then make sure that we have the amount of data that it specified: 01562 unsigned bodyOffset = nextLineStart == NULL ? fResponseBytesAlreadySeen : nextLineStart - headerDataCopy; 01563 bodyStart = &fResponseBuffer[bodyOffset]; 01564 numBodyBytes = fResponseBytesAlreadySeen - bodyOffset; 01565 if (contentLength > numBodyBytes) { 01566 // We need to read more data. First, make sure we have enough space for it: 01567 unsigned numExtraBytesNeeded = contentLength - numBodyBytes; 01568 unsigned remainingBufferSize = responseBufferSize - fResponseBytesAlreadySeen; 01569 if (numExtraBytesNeeded > remainingBufferSize) { 01570 char tmpBuf[200]; 01571 sprintf(tmpBuf, "Response buffer size (%d) is too small for \"Content-Length:\" %d (need a buffer size of >= %d bytes\n", 01572 responseBufferSize, contentLength, fResponseBytesAlreadySeen + numExtraBytesNeeded); 01573 envir().setResultMsg(tmpBuf); 01574 break; 01575 } 01576 01577 if (fVerbosityLevel >= 1) { 01578 envir() << "Have received " << fResponseBytesAlreadySeen << " total bytes of a " 01579 << (foundRequest != NULL ? foundRequest->commandName() : "(unknown)") 01580 << " RTSP response; awaiting " << numExtraBytesNeeded << " bytes more.\n"; 01581 } 01582 delete[] headerDataCopy; 01583 if (foundRequest != NULL) fRequestsAwaitingResponse.putAtHead(foundRequest);// put our request record back; we need it again 01584 return; // We need to read more data 01585 } 01586 01587 // We now have a complete response (including all bytes specified by the "Content-Length:" header, if any). 01588 char* responseEnd = bodyStart + contentLength; 01589 numExtraBytesAfterResponse = &fResponseBuffer[fResponseBytesAlreadySeen] - responseEnd; 01590 01591 if (fVerbosityLevel >= 1) { 01592 char saved = *responseEnd; 01593 *responseEnd = '\0'; 01594 envir() << "Received a complete " 01595 << (foundRequest != NULL ? foundRequest->commandName() : "(unknown)") 01596 << " response:\n" << fResponseBuffer << "\n"; 01597 if (numExtraBytesAfterResponse > 0) envir() << "\t(plus " << numExtraBytesAfterResponse << " additional bytes)\n"; 01598 *responseEnd = saved; 01599 } 01600 01601 if (foundRequest != NULL) { 01602 Boolean needToResendCommand = False; // by default... 01603 if (responseCode == 200) { 01604 // Do special-case response handling for some commands: 01605 if (strcmp(foundRequest->commandName(), "SETUP") == 0) { 01606 if (!handleSETUPResponse(*foundRequest->subsession(), sessionParamsStr, transportParamsStr, foundRequest->booleanFlags()&0x1)) break; 01607 } else if (strcmp(foundRequest->commandName(), "PLAY") == 0) { 01608 if (!handlePLAYResponse(*foundRequest->session(), *foundRequest->subsession(), scaleParamsStr, rangeParamsStr, rtpInfoParamsStr)) break; 01609 } else if (strcmp(foundRequest->commandName(), "TEARDOWN") == 0) { 01610 if (!handleTEARDOWNResponse(*foundRequest->session(), *foundRequest->subsession())) break; 01611 } else if (strcmp(foundRequest->commandName(), "GET_PARAMETER") == 0) { 01612 if (!handleGET_PARAMETERResponse(foundRequest->contentStr(), bodyStart)) break; 01613 } 01614 } else if (responseCode == 401 && handleAuthenticationFailure(wwwAuthenticateParamsStr)) { 01615 // We need to resend the command, with an "Authorization:" header: 01616 needToResendCommand = True; 01617 01618 if (strcmp(foundRequest->commandName(), "GET") == 0) { 01619 // Note: If a HTTP "GET" command (for RTSP-over-HTTP tunneling) returns "401 Unauthorized", then we resend it 01620 // (with an "Authorization:" header), just as we would for a RTSP command. However, we do so using a new TCP connection, 01621 // because some servers close the original connection after returning the "401 Unauthorized". 01622 resetTCPSockets(); // forces the opening of a new connection for the resent command 01623 } 01624 } else if (responseCode == 301 || responseCode == 302) { // redirection 01625 resetTCPSockets(); // because we need to connect somewhere else next 01626 needToResendCommand = True; 01627 } 01628 01629 if (needToResendCommand) { 01630 resetResponseBuffer(); 01631 if (!resendCommand(foundRequest)) break; 01632 delete[] headerDataCopy; 01633 return; // without calling our response handler; the response to the resent command will do that 01634 } 01635 } 01636 01637 responseSuccess = True; 01638 } while (0); 01639 01640 // If we have a handler function for this response, call it. 01641 // But first, reset our response buffer, in case the handler goes to the event loop, and we end up getting called recursively: 01642 if (numExtraBytesAfterResponse > 0) { 01643 // An unusual case; usually due to having received pipelined responses. Move the extra bytes to the front of the buffer: 01644 char* responseEnd = &fResponseBuffer[fResponseBytesAlreadySeen - numExtraBytesAfterResponse]; 01645 01646 // But first: A hack to save a copy of the response 'body', in case it's needed below for "resultString": 01647 numBodyBytes -= numExtraBytesAfterResponse; 01648 if (numBodyBytes > 0) { 01649 char saved = *responseEnd; 01650 *responseEnd = '\0'; 01651 bodyStart = strDup(bodyStart); 01652 *responseEnd = saved; 01653 } 01654 01655 memmove(fResponseBuffer, responseEnd, numExtraBytesAfterResponse); 01656 fResponseBytesAlreadySeen = numExtraBytesAfterResponse; 01657 fResponseBufferBytesLeft = responseBufferSize - numExtraBytesAfterResponse; 01658 fResponseBuffer[numExtraBytesAfterResponse] = '\0'; 01659 } else { 01660 resetResponseBuffer(); 01661 } 01662 if (foundRequest != NULL && foundRequest->handler() != NULL) { 01663 int resultCode; 01664 char* resultString; 01665 if (responseSuccess) { 01666 if (responseCode == 200) { 01667 resultCode = 0; 01668 resultString = numBodyBytes > 0 ? strDup(bodyStart) : strDup(publicParamsStr); 01669 // Note: The "strDup(bodyStart)" call assumes that the body is encoded without interior '\0' bytes 01670 } else { 01671 resultCode = responseCode; 01672 resultString = strDup(responseStr); 01673 envir().setResultMsg(responseStr); 01674 } 01675 (*foundRequest->handler())(this, resultCode, resultString); 01676 } else { 01677 // An error occurred parsing the response, so call the handler, indicating an error: 01678 handleRequestError(foundRequest); 01679 } 01680 } 01681 delete foundRequest; 01682 delete[] headerDataCopy; 01683 if (numExtraBytesAfterResponse > 0 && numBodyBytes > 0) delete[] bodyStart; 01684 } while (numExtraBytesAfterResponse > 0 && responseSuccess); 01685 }
| Boolean Medium::lookupByName | ( | UsageEnvironment & | env, | |
| char const * | mediumName, | |||
| Medium *& | resultMedium | |||
| ) | [static, inherited] |
Definition at line 41 of file Media.cpp.
References env, False, MediaLookupTable::lookup(), NULL, MediaLookupTable::ourMedia(), UsageEnvironment::setResultMsg(), and True.
Referenced by ServerMediaSession::lookupByName(), RTSPServer::lookupByName(), lookupByName(), RTCPInstance::lookupByName(), MediaSource::lookupByName(), MediaSink::lookupByName(), MediaSession::lookupByName(), and DarwinInjector::lookupByName().
00042 { 00043 resultMedium = MediaLookupTable::ourMedia(env)->lookup(mediumName); 00044 if (resultMedium == NULL) { 00045 env.setResultMsg("Medium ", mediumName, " does not exist"); 00046 return False; 00047 } 00048 00049 return True; 00050 }
| void Medium::close | ( | UsageEnvironment & | env, | |
| char const * | mediumName | |||
| ) | [static, inherited] |
Definition at line 52 of file Media.cpp.
References env, MediaLookupTable::ourMedia(), and MediaLookupTable::remove().
Referenced by afterPlaying(), Medium::close(), closeMediaSinks(), OnDemandServerMediaSubsession::closeStreamSource(), continueAfterClientCreation0(), continueAfterTEARDOWN(), WAVAudioFileSource::createNew(), QuickTimeFileSink::createNew(), QCELPAudioRTPSource::createNew(), MP3FileSource::createNew(), AVIFileSink::createNew(), AMRAudioRTPSource::createNew(), WAVAudioFileServerMediaSubsession::createNewStreamSource(), MPEG1or2DemuxedServerMediaSubsession::createNewStreamSource(), MediaSubsession::deInitiate(), ServerMediaSession::deleteAllSubsessions(), RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming::handleHTTPCmd_StreamingGET(), MediaSubsession::initiate(), MPEG1or2ProgramStreamFileDuration(), MPEG1or2Demux::noteElementaryStreamDeletion(), ByteStreamMultiFileSource::onSourceClosure1(), StreamState::reclaim(), RTSPServer::removeServerMediaSession(), ProxyServerMediaSession::resetDESCRIBEState(), OnDemandServerMediaSubsession::sdpLines(), shutdownStream(), subsessionAfterPlaying(), ClientTrickPlayState::updateStateOnScaleChange(), AMRDeinterleaver::~AMRDeinterleaver(), ByteStreamMultiFileSource::~ByteStreamMultiFileSource(), DarwinInjector::~DarwinInjector(), FramedFilter::~FramedFilter(), H264VideoRTPSink::~H264VideoRTPSink(), InputESSourceRecord::~InputESSourceRecord(), MatroskaFileParser::~MatroskaFileParser(), MatroskaFileServerDemux::~MatroskaFileServerDemux(), MPEG1or2Demux::~MPEG1or2Demux(), MPEG1or2FileServerDemux::~MPEG1or2FileServerDemux(), MPEG2TransportFileServerMediaSubsession::~MPEG2TransportFileServerMediaSubsession(), MPEG2TransportStreamFromPESSource::~MPEG2TransportStreamFromPESSource(), ProxyServerMediaSession::~ProxyServerMediaSession(), RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming::~RTSPClientConnectionSupportingHTTPStreaming(), ServerMediaSubsession::~ServerMediaSubsession(), StreamClientState::~StreamClientState(), StreamReplicator::~StreamReplicator(), and T140TextRTPSink::~T140TextRTPSink().
00052 { 00053 MediaLookupTable::ourMedia(env)->remove(name); 00054 }
| void Medium::close | ( | Medium * | medium | ) | [static, inherited] |
Definition at line 56 of file Media.cpp.
References Medium::close(), Medium::envir(), Medium::name(), and NULL.
00056 { 00057 if (medium == NULL) return; 00058 00059 close(medium->envir(), medium->name()); 00060 }
| UsageEnvironment& Medium::envir | ( | ) | const [inline, inherited] |
Definition at line 59 of file Media.hh.
References Medium::fEnviron.
Referenced by QuickTimeFileSink::addArbitraryString(), FileSink::addData(), RTCPInstance::addStreamSocket(), MPEG2IFrameIndexFromTransportStream::addToTail(), StreamParser::afterGettingBytes1(), DummySink::afterGettingFrame(), TCPStreamSink::afterGettingFrame(), T140IdleFilter::afterGettingFrame(), FileSink::afterGettingFrame(), MultiFramedRTPSink::afterGettingFrame1(), InputESSourceRecord::afterGettingFrame1(), MPEG2TransportStreamFramer::afterGettingFrame1(), MPEG2IFrameIndexFromTransportStream::afterGettingFrame1(), H264VideoStreamDiscreteFramer::afterGettingFrame1(), BasicUDPSink::afterGettingFrame1(), MPEG4VideoFileServerMediaSubsession::afterPlayingDummy1(), H264VideoFileServerMediaSubsession::afterPlayingDummy1(), MPEG4VideoStreamParser::analyzeVOLHeader(), announceStream(), RTSPServer::RTSPClientConnection::changeClientInputSocket(), MPEG4VideoFileServerMediaSubsession::checkForAuxSDPLine1(), H264VideoFileServerMediaSubsession::checkForAuxSDPLine1(), Medium::close(), ProxyServerMediaSubsession::closeStreamSource(), MPEG2IFrameIndexFromTransportStream::compactParseBuffer(), connectionHandler1(), connectToServer(), ProxyServerMediaSession::continueAfterDESCRIBE(), ProxyRTSPClient::continueAfterLivenessCommand(), ProxyRTSPClient::continueAfterSETUP(), T140TextRTPSink::continuePlaying(), QuickTimeFileSink::continuePlaying(), H264VideoRTPSink::continuePlaying(), AVIFileSink::continuePlaying(), RTSPServer::continueRegisterStream(), VP8VideoMatroskaFileServerMediaSubsession::createNewRTPSink(), VorbisAudioMatroskaFileServerMediaSubsession::createNewRTPSink(), T140TextMatroskaFileServerMediaSubsession::createNewRTPSink(), ProxyServerMediaSubsession::createNewRTPSink(), MPEG4VideoFileServerMediaSubsession::createNewRTPSink(), MPEG2TransportUDPServerMediaSubsession::createNewRTPSink(), MPEG2TransportFileServerMediaSubsession::createNewRTPSink(), MPEG1or2VideoFileServerMediaSubsession::createNewRTPSink(), MPEG1or2DemuxedServerMediaSubsession::createNewRTPSink(), MP3AudioFileServerMediaSubsession::createNewRTPSink(), H264VideoFileServerMediaSubsession::createNewRTPSink(), H263plusVideoFileServerMediaSubsession::createNewRTPSink(), DVVideoFileServerMediaSubsession::createNewRTPSink(), AMRAudioFileServerMediaSubsession::createNewRTPSink(), ADTSAudioFileServerMediaSubsession::createNewRTPSink(), AC3AudioMatroskaFileServerMediaSubsession::createNewRTPSink(), AC3AudioFileServerMediaSubsession::createNewRTPSink(), AACAudioMatroskaFileServerMediaSubsession::createNewRTPSink(), HandlerServerForREGISTERCommand::createNewRTSPClient(), ProxyServerMediaSubsession::createNewStreamSource(), MPEG4VideoFileServerMediaSubsession::createNewStreamSource(), MPEG2TransportUDPServerMediaSubsession::createNewStreamSource(), MPEG2TransportFileServerMediaSubsession::createNewStreamSource(), MPEG1or2VideoFileServerMediaSubsession::createNewStreamSource(), MPEG1or2DemuxedServerMediaSubsession::createNewStreamSource(), MP3AudioFileServerMediaSubsession::createNewStreamSource(), H264VideoMatroskaFileServerMediaSubsession::createNewStreamSource(), H264VideoFileServerMediaSubsession::createNewStreamSource(), H263plusVideoFileServerMediaSubsession::createNewStreamSource(), DVVideoFileServerMediaSubsession::createNewStreamSource(), AMRAudioFileServerMediaSubsession::createNewStreamSource(), ADTSAudioFileServerMediaSubsession::createNewStreamSource(), AC3AudioFileServerMediaSubsession::createNewStreamSource(), AMRDeinterleavingBuffer::deliverIncomingFrame(), MPEG2IFrameIndexFromTransportStream::deliverIndexRecord(), SegmentQueue::dequeue(), DeviceSource::DeviceSource(), WAVAudioFileSource::doGetNextFrame(), T140IdleFilter::doGetNextFrame(), MPEG2TransportStreamMultiplexor::doGetNextFrame(), MPEG2IFrameIndexFromTransportStream::doGetNextFrame(), MP3FileSource::doGetNextFrame(), H264FUAFragmenter::doGetNextFrame(), ByteStreamMultiFileSource::doGetNextFrame(), ByteStreamFileSource::doGetNextFrame(), BasicUDPSource::doGetNextFrame(), AMRAudioFileSource::doGetNextFrame(), ADTSAudioFileSource::doGetNextFrame(), MultiFramedRTPSource::doGetNextFrame1(), MP3FileSource::doGetNextFrame1(), ADUFromMP3Source::doGetNextFrame1(), SIPClient::doInviteStateMachine(), WAVAudioFileSource::doReadFromFile(), ByteStreamFileSource::doReadFromFile(), MPEG1or2VideoRTPSink::doSpecialFrameHandling(), MP3ADURTPSink::doSpecialFrameHandling(), H263plusVideoRTPSink::doSpecialFrameHandling(), WAVAudioFileSource::doStopGettingFrames(), T140IdleFilter::doStopGettingFrames(), MultiFramedRTPSource::doStopGettingFrames(), FramedSource::doStopGettingFrames(), ByteStreamFileSource::doStopGettingFrames(), BasicUDPSource::doStopGettingFrames(), SegmentQueue::enqueueNewSegment(), StreamParser::ensureValidBytes1(), MediaSubsession::env(), SubsessionIOState::envir(), RTSPServer::RegisterRequestRecord::envir(), RTSPServer::RTSPClientSession::envir(), RTSPServer::RTSPClientConnection::envir(), RTPInterface::envir(), AVISubsessionIOState::envir(), ServerMediaSession::generateSDPDescription(), RTPSource::getAttributes(), MP3FileSource::getAttributes(), MP3ADUTranscoder::getAttributes(), MediaSource::getAttributes(), MPEG4VideoFileServerMediaSubsession::getAuxSDPLine(), H264VideoFileServerMediaSubsession::getAuxSDPLine(), getMPEG1or2TimeCode(), FramedSource::getNextFrame(), getOptions(), DVVideoStreamFramer::getProfile(), SIPClient::getResponse(), SIPClient::getResponseCode(), getSDPDescription(), OnDemandServerMediaSubsession::getStreamParameters(), handleAlternativeRequestByte1(), handleGET_PARAMETERResponse(), RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming::handleHTTPCmd_StreamingGET(), handleIncomingRequest(), handlePLAYResponse(), handleRequestError(), handleResponseBytes(), handleSETUPResponse(), RTSPServerWithREGISTERProxying::implementCmd_REGISTER(), RTSPServer::incomingConnectionHandler(), incomingDataHandler1(), RTCPInstance::incomingReportHandler1(), MP3FileSource::initializeStream(), MediaSession::initializeWithSDP(), MediaSession::initiateByMediaType(), SIPClient::invite1(), DynamicRTSPServer::lookupServerMediaSession(), MatroskaDemux::MatroskaDemux(), MatroskaFile::MatroskaFile(), MPEG4GenericRTPSource::MPEG4GenericRTPSource(), MultiFramedRTPSource::networkReadHandler1(), MatroskaDemux::newDemuxedTrack(), MPEG1or2FileServerDemux::newElementaryStream(), MPEG1or2Demux::newElementaryStream(), MPEG4GenericBufferedPacket::nextEnclosedFrameSize(), AMRBufferedPacket::nextEnclosedFrameSize(), T140IdleFilter::onSourceClosure(), openConnection(), MPEG2TransportStreamIndexFile::openFid(), MPEG2IFrameIndexFromTransportStream::parseFrame(), AC3AudioStreamParser::parseFrame(), MPEGProgramStreamParser::parsePackHeader(), MPEGProgramStreamParser::parsePESPacket(), SIPClient::parseResponseCode(), MediaSession::parseSDPLine(), MPEG1or2VideoStreamParser::parseSlice(), MatroskaFileParser::parseStartOfFile(), MPEGProgramStreamParser::parseSystemHeader(), MPEG4VideoStreamParser::parseVideoObjectLayer(), MPEG4VideoStreamParser::parseVideoObjectPlane(), MPEG4VideoStreamParser::parseVisualObject(), TCPStreamSink::processBuffer(), SIPClient::processURL(), AC3AudioStreamParser::readAndSaveAFrame(), MPEG1or2Demux::registerReadInterest(), RTSPServer::registerStream(), RTCPInstance::reschedule(), resendCommand(), ProxyRTSPClient::reset(), resetTCPSockets(), responseHandlerForHTTP_GET1(), RTSPClient(), RTSPServer::rtspURLPrefix(), RTCPInstance::schedule(), ProxyRTSPClient::scheduleDESCRIBECommand(), ProxyRTSPClient::scheduleLivenessCommand(), OnDemandServerMediaSubsession::sdpLines(), SIPClient::sendACK(), SIPClient::sendBYE(), SIPClient::sendINVITE(), MultiFramedRTPSink::sendPacketIfNecessary(), SIPClient::sendRequest(), sendRequest(), DarwinInjector::setDestination(), setupHTTPTunneling1(), setupNextSubsession(), RTSPServer::setUpTunnelingOverHTTP(), QuickTimeFileSink::setWord(), AVIFileSink::setWord(), QuickTimeFileSink::setWord64(), shutdownStream(), SIPClient::SIPClient(), TCPStreamSink::socketWritableHandler1(), AMRAudioRTPSink::sourceIsCompatibleWithUs(), QuickTimeFileSink::startPlaying(), StreamState::startPlaying(), MediaSink::startPlaying(), AVIFileSink::startPlaying(), startPlayingSession(), PassiveServerMediaSubsession::startStream(), MediaSink::stopPlaying(), ProxyServerMediaSubsession::subsessionByeHandler(), tearDownSession(), SIPClient::timerAHandler(), SIPClient::timerBHandler(), SIPClient::timerDHandler(), ClientTrickPlayState::updateStateOnScaleChange(), MPEG2TransportStreamFramer::updateTSPacketDurationEstimate(), BasicUDPSource::~BasicUDPSource(), ByteStreamFileSource::~ByteStreamFileSource(), DeviceSource::~DeviceSource(), ProxyServerMediaSession::~ProxyServerMediaSession(), ProxyServerMediaSubsession::~ProxyServerMediaSubsession(), RTSPServer::~RTSPServer(), StreamClientState::~StreamClientState(), T140IdleFilter::~T140IdleFilter(), and WAVAudioFileSource::~WAVAudioFileSource().
00059 {return fEnviron;}
| char const* Medium::name | ( | ) | const [inline, inherited] |
Definition at line 61 of file Media.hh.
References Medium::fMediumName.
Referenced by QuickTimeFileSink::addAtom_hdlr2(), Medium::close(), MP3ADUTranscoder::createNew(), MP3FromADUSource::createNew(), ADUFromMP3Source::createNew(), and MP3FileSource::initializeStream().
00061 {return fMediumName;}
| Boolean Medium::isSource | ( | ) | const [virtual, inherited] |
Reimplemented in MediaSource.
Definition at line 62 of file Media.cpp.
References False.
Referenced by MediaSource::lookupByName().
00062 { 00063 return False; // default implementation 00064 }
| Boolean Medium::isSink | ( | ) | const [virtual, inherited] |
| Boolean Medium::isRTCPInstance | ( | ) | const [virtual, inherited] |
Reimplemented in RTCPInstance.
Definition at line 70 of file Media.cpp.
References False.
Referenced by RTCPInstance::lookupByName().
00070 { 00071 return False; // default implementation 00072 }
| Boolean Medium::isRTSPServer | ( | ) | const [virtual, inherited] |
Reimplemented in RTSPServer.
Definition at line 78 of file Media.cpp.
References False.
Referenced by RTSPServer::lookupByName().
00078 { 00079 return False; // default implementation 00080 }
| Boolean Medium::isMediaSession | ( | ) | const [virtual, inherited] |
Reimplemented in MediaSession.
Definition at line 82 of file Media.cpp.
References False.
Referenced by MediaSession::lookupByName().
00082 { 00083 return False; // default implementation 00084 }
| Boolean Medium::isServerMediaSession | ( | ) | const [virtual, inherited] |
Reimplemented in ServerMediaSession.
Definition at line 86 of file Media.cpp.
References False.
Referenced by ServerMediaSession::lookupByName().
00086 { 00087 return False; // default implementation 00088 }
| Boolean Medium::isDarwinInjector | ( | ) | const [virtual, inherited] |
Reimplemented in DarwinInjector.
Definition at line 90 of file Media.cpp.
References False.
Referenced by DarwinInjector::lookupByName().
00090 { 00091 return False; // default implementation 00092 }
| TaskToken& Medium::nextTask | ( | ) | [inline, protected, inherited] |
Definition at line 78 of file Media.hh.
References Medium::fNextTask.
Referenced by BasicUDPSink::afterGettingFrame1(), MPEG4VideoFileServerMediaSubsession::afterPlayingDummy1(), H264VideoFileServerMediaSubsession::afterPlayingDummy1(), MPEG4VideoFileServerMediaSubsession::checkForAuxSDPLine1(), H264VideoFileServerMediaSubsession::checkForAuxSDPLine1(), MP3FileSource::doGetNextFrame(), AMRAudioFileSource::doGetNextFrame(), ADTSAudioFileSource::doGetNextFrame(), MultiFramedRTPSource::doGetNextFrame1(), WAVAudioFileSource::doReadFromFile(), ByteStreamFileSource::doReadFromFile(), MultiFramedRTPSource::doStopGettingFrames(), FramedSource::doStopGettingFrames(), ByteStreamFileSource::doStopGettingFrames(), RTCPInstance::reschedule(), RTCPInstance::schedule(), MultiFramedRTPSink::sendPacketIfNecessary(), and MediaSink::stopPlaying().
00078 { 00079 return fNextTask; 00080 }
friend class MediaLookupTable [friend, inherited] |
unsigned RTSPClient::responseBufferSize = 20000 [static] |
Definition at line 172 of file RTSPClient.hh.
Referenced by handleResponseBytes(), handleSETUPResponse(), resetResponseBuffer(), and RTSPClient().
int RTSPClient::fVerbosityLevel [protected] |
Definition at line 292 of file RTSPClient.hh.
Referenced by connectionHandler1(), connectToServer(), ProxyRTSPClient::continueAfterLivenessCommand(), ProxyRTSPClient::continueAfterSETUP(), handleIncomingRequest(), handleResponseBytes(), resendCommand(), ProxyRTSPClient::scheduleDESCRIBECommand(), sendRequest(), and setupHTTPTunneling1().
unsigned RTSPClient::fCSeq [protected] |
Definition at line 293 of file RTSPClient.hh.
Referenced by resendCommand(), sendAnnounceCommand(), sendDescribeCommand(), sendGetParameterCommand(), sendOptionsCommand(), sendPauseCommand(), sendPlayCommand(), sendRecordCommand(), sendSetParameterCommand(), sendSetupCommand(), and sendTeardownCommand().
Authenticator RTSPClient::fCurrentAuthenticator [protected] |
Definition at line 294 of file RTSPClient.hh.
Referenced by createAuthenticatorString(), handleAuthenticationFailure(), openConnection(), reset(), sendAnnounceCommand(), sendDescribeCommand(), sendGetParameterCommand(), sendOptionsCommand(), sendPauseCommand(), sendPlayCommand(), sendRecordCommand(), sendSetParameterCommand(), sendSetupCommand(), and sendTeardownCommand().
Definition at line 297 of file RTSPClient.hh.
Referenced by openConnection(), responseHandlerForHTTP_GET1(), sendRequest(), sendSetupCommand(), and setupHTTPTunneling1().
char* RTSPClient::fUserAgentHeaderStr [private] |
Definition at line 298 of file RTSPClient.hh.
Referenced by sendRequest(), setUserAgentString(), and ~RTSPClient().
unsigned RTSPClient::fUserAgentHeaderStrLen [private] |
Definition at line 299 of file RTSPClient.hh.
Referenced by sendRequest(), and setUserAgentString().
int RTSPClient::fInputSocketNum [private] |
Definition at line 300 of file RTSPClient.hh.
Referenced by connectionHandler1(), handleAlternativeRequestByte1(), handleSETUPResponse(), incomingDataHandler1(), openConnection(), resetTCPSockets(), RTSPClient(), sendRequest(), and socketNum().
int RTSPClient::fOutputSocketNum [private] |
Definition at line 300 of file RTSPClient.hh.
Referenced by connectionHandler1(), handleIncomingRequest(), openConnection(), resetTCPSockets(), responseHandlerForHTTP_GET1(), RTSPClient(), and sendRequest().
netAddressBits RTSPClient::fServerAddress [private] |
Definition at line 301 of file RTSPClient.hh.
Referenced by connectToServer(), handleSETUPResponse(), openConnection(), and reset().
char* RTSPClient::fBaseURL [private] |
Definition at line 302 of file RTSPClient.hh.
Referenced by openConnection(), sendRequest(), sessionURL(), setBaseURL(), and url().
unsigned char RTSPClient::fTCPStreamIdCount [private] |
char* RTSPClient::fLastSessionId [private] |
Definition at line 304 of file RTSPClient.hh.
Referenced by handleSETUPResponse(), reset(), and sendRequest().
unsigned RTSPClient::fSessionTimeoutParameter [private] |
Definition at line 305 of file RTSPClient.hh.
Referenced by handleSETUPResponse(), and sessionTimeoutParameter().
char* RTSPClient::fResponseBuffer [private] |
Definition at line 306 of file RTSPClient.hh.
Referenced by handleAlternativeRequestByte1(), handleIncomingRequest(), handleResponseBytes(), incomingDataHandler1(), RTSPClient(), and ~RTSPClient().
unsigned RTSPClient::fResponseBytesAlreadySeen [private] |
Definition at line 307 of file RTSPClient.hh.
Referenced by handleAlternativeRequestByte1(), handleIncomingRequest(), handleResponseBytes(), incomingDataHandler1(), and resetResponseBuffer().
unsigned RTSPClient::fResponseBufferBytesLeft [private] |
Definition at line 307 of file RTSPClient.hh.
Referenced by handleResponseBytes(), incomingDataHandler1(), and resetResponseBuffer().
Definition at line 308 of file RTSPClient.hh.
Referenced by changeResponseHandler(), connectionHandler1(), responseHandlerForHTTP_GET1(), and sendRequest().
Definition at line 308 of file RTSPClient.hh.
Referenced by changeResponseHandler(), responseHandlerForHTTP_GET1(), and sendRequest().
Definition at line 308 of file RTSPClient.hh.
Referenced by changeResponseHandler(), handleResponseBytes(), and sendRequest().
char RTSPClient::fSessionCookie[33] [private] |
unsigned RTSPClient::fSessionCookieCounter [private] |
Definition at line 313 of file RTSPClient.hh.
Referenced by connectionHandler1(), responseHandlerForHTTP_GET1(), and setupHTTPTunneling2().
1.5.2