| 1 | /********** |
| 2 | This library is free software; you can redistribute it and/or modify it under |
| 3 | the terms of the GNU Lesser General Public License as published by the |
| 4 | Free Software Foundation; either version 3 of the License, or (at your |
| 5 | option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) |
| 6 | |
| 7 | This library is distributed in the hope that it will be useful, but WITHOUT |
| 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for |
| 10 | more details. |
| 11 | |
| 12 | You should have received a copy of the GNU Lesser General Public License |
| 13 | along with this library; if not, write to the Free Software Foundation, Inc., |
| 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 15 | **********/ |
| 16 | // "liveMedia" |
| 17 | // Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved. |
| 18 | // A generic RTSP client - for a single "rtsp://" URL |
| 19 | // C++ header |
| 20 | |
| 21 | #ifndef _RTSP_CLIENT_HH |
| 22 | #define _RTSP_CLIENT_HH |
| 23 | |
| 24 | #ifndef _MEDIA_SESSION_HH |
| 25 | #include "MediaSession.hh" |
| 26 | #endif |
| 27 | #ifndef _NET_ADDRESS_HH |
| 28 | #include "NetAddress.hh" |
| 29 | #endif |
| 30 | #ifndef _DIGEST_AUTHENTICATION_HH |
| 31 | #include "DigestAuthentication.hh" |
| 32 | #endif |
| 33 | #ifndef _TLS_STATE_HH |
| 34 | #include "TLSState.hh" |
| 35 | #endif |
| 36 | #ifndef OMIT_REGISTER_HANDLING |
| 37 | #ifndef _RTSP_SERVER_HH |
| 38 | #include "RTSPServer.hh" // For the optional "HandlerForREGISTERCommand" mini-server |
| 39 | #endif |
| 40 | #endif |
| 41 | |
| 42 | class RTSPClient: public Medium { |
| 43 | public: |
| 44 | static RTSPClient* createNew(UsageEnvironment& env, char const* rtspURL, |
| 45 | int verbosityLevel = 0, |
| 46 | char const* applicationName = NULL, |
| 47 | portNumBits tunnelOverHTTPPortNum = 0, |
| 48 | int socketNumToServer = -1); |
| 49 | // If "tunnelOverHTTPPortNum" is non-zero, we tunnel RTSP (and RTP) |
| 50 | // over a HTTP connection with the given port number, using the technique |
| 51 | // described in Apple's document <http://developer.apple.com/documentation/QuickTime/QTSS/Concepts/chapter_2_section_14.html> |
| 52 | // If "socketNumToServer" is >= 0, then it is the socket number of an already-existing TCP connection to the server. |
| 53 | // (In this case, "rtspURL" must point to the socket's endpoint, so that it can be accessed via the socket.) |
| 54 | |
| 55 | typedef void (responseHandler)(RTSPClient* rtspClient, |
| 56 | int resultCode, char* resultString); |
| 57 | // A function that is called in response to a RTSP command. The parameters are as follows: |
| 58 | // "rtspClient": The "RTSPClient" object on which the original command was issued. |
| 59 | // "resultCode": If zero, then the command completed successfully. If non-zero, then the command did not complete |
| 60 | // successfully, and "resultCode" indicates the error, as follows: |
| 61 | // A positive "resultCode" is a RTSP error code (for example, 404 means "not found") |
| 62 | // A negative "resultCode" indicates a socket/network error; 0-"resultCode" is the standard "errno" code. |
| 63 | // "resultString": A ('\0'-terminated) string returned along with the response, or else NULL. |
| 64 | // In particular: |
| 65 | // "resultString" for a successful "DESCRIBE" command will be the media session's SDP description. |
| 66 | // "resultString" for a successful "OPTIONS" command will be a list of allowed commands. |
| 67 | // Note that this string can be present (i.e., not NULL) even if "resultCode" is non-zero - i.e., an error message. |
| 68 | // Also, "resultString" can be NULL, even if "resultCode" is zero (e.g., if the RTSP command succeeded, but without |
| 69 | // including an appropriate result header). |
| 70 | // Note also that this string is dynamically allocated, and must be freed by the handler (or the caller) |
| 71 | // - using "delete[]". |
| 72 | |
| 73 | unsigned sendDescribeCommand(responseHandler* responseHandler, Authenticator* authenticator = NULL); |
| 74 | // Issues a RTSP "DESCRIBE" command, then returns the "CSeq" sequence number that was used in the command. |
| 75 | // The (programmer-supplied) "responseHandler" function is called later to handle the response |
| 76 | // (or is called immediately - with an error code - if the command cannot be sent). |
| 77 | // "authenticator" (optional) is used for access control. If you have username and password strings, you can use this by |
| 78 | // passing an actual parameter that you created by creating an "Authenticator(username, password) object". |
| 79 | // (Note that if you supply a non-NULL "authenticator" parameter, you need do this only for the first command you send.) |
| 80 | |
| 81 | unsigned sendOptionsCommand(responseHandler* responseHandler, Authenticator* authenticator = NULL); |
| 82 | // Issues a RTSP "OPTIONS" command, then returns the "CSeq" sequence number that was used in the command. |
| 83 | // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) |
| 84 | |
| 85 | unsigned sendAnnounceCommand(char const* sdpDescription, responseHandler* responseHandler, Authenticator* authenticator = NULL); |
| 86 | // Issues a RTSP "ANNOUNCE" command (with "sdpDescription" as parameter), |
| 87 | // then returns the "CSeq" sequence number that was used in the command. |
| 88 | // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) |
| 89 | |
| 90 | unsigned sendSetupCommand(MediaSubsession& subsession, responseHandler* responseHandler, |
| 91 | Boolean streamOutgoing = False, |
| 92 | Boolean streamUsingTCP = False, |
| 93 | Boolean forceMulticastOnUnspecified = False, |
| 94 | Authenticator* authenticator = NULL); |
| 95 | // Issues a RTSP "SETUP" command, then returns the "CSeq" sequence number that was used in the command. |
| 96 | // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) |
| 97 | |
| 98 | unsigned sendPlayCommand(MediaSession& session, responseHandler* responseHandler, |
| 99 | double start = 0.0f, double end = -1.0f, float scale = 1.0f, |
| 100 | Authenticator* authenticator = NULL); |
| 101 | // Issues an aggregate RTSP "PLAY" command on "session", then returns the "CSeq" sequence number that was used in the command. |
| 102 | // (Note: start=-1 means 'resume'; end=-1 means 'play to end') |
| 103 | // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) |
| 104 | unsigned sendPlayCommand(MediaSubsession& subsession, responseHandler* responseHandler, |
| 105 | double start = 0.0f, double end = -1.0f, float scale = 1.0f, |
| 106 | Authenticator* authenticator = NULL); |
| 107 | // Issues a RTSP "PLAY" command on "subsession", then returns the "CSeq" sequence number that was used in the command. |
| 108 | // (Note: start=-1 means 'resume'; end=-1 means 'play to end') |
| 109 | // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) |
| 110 | |
| 111 | // Alternative forms of "sendPlayCommand()", used to send "PLAY" commands that include an 'absolute' time range: |
| 112 | // (The "absStartTime" string (and "absEndTime" string, if present) *must* be of the form |
| 113 | // "YYYYMMDDTHHMMSSZ" or "YYYYMMDDTHHMMSS.<frac>Z") |
| 114 | unsigned sendPlayCommand(MediaSession& session, responseHandler* responseHandler, |
| 115 | char const* absStartTime, char const* absEndTime = NULL, float scale = 1.0f, |
| 116 | Authenticator* authenticator = NULL); |
| 117 | unsigned sendPlayCommand(MediaSubsession& subsession, responseHandler* responseHandler, |
| 118 | char const* absStartTime, char const* absEndTime = NULL, float scale = 1.0f, |
| 119 | Authenticator* authenticator = NULL); |
| 120 | |
| 121 | unsigned sendPauseCommand(MediaSession& session, responseHandler* responseHandler, Authenticator* authenticator = NULL); |
| 122 | // Issues an aggregate RTSP "PAUSE" command on "session", then returns the "CSeq" sequence number that was used in the command. |
| 123 | // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) |
| 124 | unsigned sendPauseCommand(MediaSubsession& subsession, responseHandler* responseHandler, Authenticator* authenticator = NULL); |
| 125 | // Issues a RTSP "PAUSE" command on "subsession", then returns the "CSeq" sequence number that was used in the command. |
| 126 | // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) |
| 127 | |
| 128 | unsigned sendRecordCommand(MediaSession& session, responseHandler* responseHandler, Authenticator* authenticator = NULL); |
| 129 | // Issues an aggregate RTSP "RECORD" command on "session", then returns the "CSeq" sequence number that was used in the command. |
| 130 | // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) |
| 131 | unsigned sendRecordCommand(MediaSubsession& subsession, responseHandler* responseHandler, Authenticator* authenticator = NULL); |
| 132 | // Issues a RTSP "RECORD" command on "subsession", then returns the "CSeq" sequence number that was used in the command. |
| 133 | // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) |
| 134 | |
| 135 | unsigned sendTeardownCommand(MediaSession& session, responseHandler* responseHandler, Authenticator* authenticator = NULL); |
| 136 | // Issues an aggregate RTSP "TEARDOWN" command on "session", then returns the "CSeq" sequence number that was used in the command. |
| 137 | // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) |
| 138 | unsigned sendTeardownCommand(MediaSubsession& subsession, responseHandler* responseHandler, Authenticator* authenticator = NULL); |
| 139 | // Issues a RTSP "TEARDOWN" command on "subsession", then returns the "CSeq" sequence number that was used in the command. |
| 140 | // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) |
| 141 | |
| 142 | unsigned sendSetParameterCommand(MediaSession& session, responseHandler* responseHandler, |
| 143 | char const* parameterName, char const* parameterValue, |
| 144 | Authenticator* authenticator = NULL); |
| 145 | // Issues an aggregate RTSP "SET_PARAMETER" command on "session", then returns the "CSeq" sequence number that was used in the command. |
| 146 | // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) |
| 147 | |
| 148 | unsigned sendGetParameterCommand(MediaSession& session, responseHandler* responseHandler, char const* parameterName, |
| 149 | Authenticator* authenticator = NULL); |
| 150 | // Issues an aggregate RTSP "GET_PARAMETER" command on "session", then returns the "CSeq" sequence number that was used in the command. |
| 151 | // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) |
| 152 | |
| 153 | void sendDummyUDPPackets(MediaSession& session, unsigned numDummyPackets = 2); |
| 154 | void sendDummyUDPPackets(MediaSubsession& subsession, unsigned numDummyPackets = 2); |
| 155 | // Sends short 'dummy' (i.e., non-RTP or RTCP) UDP packets towards the server, to increase |
| 156 | // the likelihood of RTP/RTCP packets from the server reaching us if we're behind a NAT. |
| 157 | // (If we requested RTP-over-TCP streaming, then these functions have no effect.) |
| 158 | // Our implementation automatically does this just prior to sending each "PLAY" command; |
| 159 | // You should not call these functions yourself unless you know what you're doing. |
| 160 | |
| 161 | void setSpeed(MediaSession& session, float speed = 1.0f); |
| 162 | // Set (recorded) media download speed to given value to support faster download using 'Speed:' |
| 163 | // option on 'PLAY' command. |
| 164 | |
| 165 | Boolean changeResponseHandler(unsigned cseq, responseHandler* newResponseHandler); |
| 166 | // Changes the response handler for the previously-performed command (whose operation returned "cseq"). |
| 167 | // (To turn off any response handling for the command, use a "newResponseHandler" value of NULL. This might be done as part |
| 168 | // of an implementation of a 'timeout handler' on the command, for example.) |
| 169 | // This function returns True iff "cseq" was for a valid previously-performed command (whose response is still unhandled). |
| 170 | |
| 171 | int socketNum() const { return fInputSocketNum; } |
| 172 | |
| 173 | static Boolean lookupByName(UsageEnvironment& env, |
| 174 | char const* sourceName, |
| 175 | RTSPClient*& resultClient); |
| 176 | |
| 177 | Boolean parseRTSPURL(char const* url, |
| 178 | char*& username, char*& password, NetAddress& address, portNumBits& portNum, char const** urlSuffix = NULL); |
| 179 | // Parses "url" as "rtsp://[<username>[:<password>]@]<server-address-or-name>[:<port>][/<stream-name>]" |
| 180 | // (Note that the returned "username" and "password" are either NULL, or heap-allocated strings that the caller must later delete[].) |
| 181 | |
| 182 | void setUserAgentString(char const* userAgentName); |
| 183 | // sets an alternative string to be used in RTSP "User-Agent:" headers |
| 184 | |
| 185 | void disallowBasicAuthentication() { fAllowBasicAuthentication = False; } |
| 186 | // call this if you don't want the server to request 'Basic' authentication |
| 187 | // (which would cause the client to send usernames and passwords over the net). |
| 188 | |
| 189 | unsigned sessionTimeoutParameter() const { return fSessionTimeoutParameter; } |
| 190 | |
| 191 | char const* url() const { return fBaseURL; } |
| 192 | |
| 193 | void useTLS() { fTLS.isNeeded = True; } |
| 194 | |
| 195 | static unsigned responseBufferSize; |
| 196 | |
| 197 | public: // Some compilers complain if this is "private:" |
| 198 | // The state of a request-in-progress: |
| 199 | class RequestRecord { |
| 200 | public: |
| 201 | RequestRecord(unsigned cseq, char const* commandName, responseHandler* handler, |
| 202 | MediaSession* session = NULL, MediaSubsession* subsession = NULL, u_int32_t booleanFlags = 0, |
| 203 | double start = 0.0f, double end = -1.0f, float scale = 1.0f, char const* contentStr = NULL); |
| 204 | RequestRecord(unsigned cseq, responseHandler* handler, |
| 205 | char const* absStartTime, char const* absEndTime = NULL, float scale = 1.0f, |
| 206 | MediaSession* session = NULL, MediaSubsession* subsession = NULL); |
| 207 | // alternative constructor for creating "PLAY" requests that include 'absolute' time values |
| 208 | virtual ~RequestRecord(); |
| 209 | |
| 210 | RequestRecord*& next() { return fNext; } |
| 211 | unsigned& cseq() { return fCSeq; } |
| 212 | char const* commandName() const { return fCommandName; } |
| 213 | MediaSession* session() const { return fSession; } |
| 214 | MediaSubsession* subsession() const { return fSubsession; } |
| 215 | u_int32_t booleanFlags() const { return fBooleanFlags; } |
| 216 | double start() const { return fStart; } |
| 217 | double end() const { return fEnd; } |
| 218 | char const* absStartTime() const { return fAbsStartTime; } |
| 219 | char const* absEndTime() const { return fAbsEndTime; } |
| 220 | float scale() const { return fScale; } |
| 221 | char* contentStr() const { return fContentStr; } |
| 222 | responseHandler*& handler() { return fHandler; } |
| 223 | |
| 224 | private: |
| 225 | RequestRecord* fNext; |
| 226 | unsigned fCSeq; |
| 227 | char const* fCommandName; |
| 228 | MediaSession* fSession; |
| 229 | MediaSubsession* fSubsession; |
| 230 | u_int32_t fBooleanFlags; |
| 231 | double fStart, fEnd; |
| 232 | char *fAbsStartTime, *fAbsEndTime; // used for optional 'absolute' (i.e., "time=") range specifications |
| 233 | float fScale; |
| 234 | char* fContentStr; |
| 235 | responseHandler* fHandler; |
| 236 | }; |
| 237 | |
| 238 | protected: |
| 239 | RTSPClient(UsageEnvironment& env, char const* rtspURL, |
| 240 | int verbosityLevel, char const* applicationName, portNumBits tunnelOverHTTPPortNum, int socketNumToServer); |
| 241 | // called only by createNew(); |
| 242 | virtual ~RTSPClient(); |
| 243 | |
| 244 | void reset(); |
| 245 | void setBaseURL(char const* url); |
| 246 | int grabSocket(); // allows a subclass to reuse our input socket, so that it won't get closed when we're deleted |
| 247 | virtual unsigned sendRequest(RequestRecord* request); |
| 248 | virtual Boolean setRequestFields(RequestRecord* request, |
| 249 | char*& cmdURL, Boolean& cmdURLWasAllocated, |
| 250 | char const*& protocolStr, |
| 251 | char*& , Boolean& ); |
| 252 | // used to implement "sendRequest()"; subclasses may reimplement this (e.g., when implementing a new command name) |
| 253 | virtual int connectToServer(int socketNum, portNumBits remotePortNum); // used to implement "openConnection()"; result values: -1: failure; 0: pending; 1: success |
| 254 | |
| 255 | private: // redefined virtual functions |
| 256 | virtual Boolean isRTSPClient() const; |
| 257 | |
| 258 | private: |
| 259 | class RequestQueue { |
| 260 | public: |
| 261 | RequestQueue(); |
| 262 | RequestQueue(RequestQueue& origQueue); // moves the queue contents to the new queue |
| 263 | virtual ~RequestQueue(); |
| 264 | |
| 265 | void enqueue(RequestRecord* request); // "request" must not be NULL |
| 266 | RequestRecord* dequeue(); |
| 267 | void putAtHead(RequestRecord* request); // "request" must not be NULL |
| 268 | RequestRecord* findByCSeq(unsigned cseq); |
| 269 | Boolean isEmpty() const { return fHead == NULL; } |
| 270 | void reset(); |
| 271 | |
| 272 | private: |
| 273 | RequestRecord* fHead; |
| 274 | RequestRecord* fTail; |
| 275 | }; |
| 276 | |
| 277 | void resetTCPSockets(); |
| 278 | void resetResponseBuffer(); |
| 279 | int openConnection(); // result values: -1: failure; 0: pending; 1: success |
| 280 | char* createAuthenticatorString(char const* cmd, char const* url); |
| 281 | char* createBlocksizeString(Boolean streamUsingTCP); |
| 282 | void handleRequestError(RequestRecord* request); |
| 283 | Boolean parseResponseCode(char const* line, unsigned& responseCode, char const*& responseString); |
| 284 | void handleIncomingRequest(); |
| 285 | static Boolean (char const* line, char const* , unsigned , char const*& ); |
| 286 | Boolean parseTransportParams(char const* paramsStr, |
| 287 | char*& serverAddressStr, portNumBits& serverPortNum, |
| 288 | unsigned char& rtpChannelId, unsigned char& rtcpChannelId); |
| 289 | Boolean parseScaleParam(char const* paramStr, float& scale); |
| 290 | Boolean parseSpeedParam(char const* paramStr, float& speed); |
| 291 | Boolean parseRTPInfoParams(char const*& paramStr, u_int16_t& seqNum, u_int32_t& timestamp); |
| 292 | Boolean handleSETUPResponse(MediaSubsession& subsession, char const* sessionParamsStr, char const* transportParamsStr, |
| 293 | Boolean streamUsingTCP); |
| 294 | Boolean handlePLAYResponse(MediaSession* session, MediaSubsession* subsession, |
| 295 | char const* scaleParamsStr, const char* speedParamsStr, |
| 296 | char const* rangeParamsStr, char const* rtpInfoParamsStr); |
| 297 | Boolean handleTEARDOWNResponse(MediaSession& session, MediaSubsession& subsession); |
| 298 | Boolean handleGET_PARAMETERResponse(char const* parameterName, char*& resultValueString, char* resultValueStringEnd); |
| 299 | Boolean handleAuthenticationFailure(char const* wwwAuthenticateParamsStr); |
| 300 | Boolean resendCommand(RequestRecord* request); |
| 301 | char const* sessionURL(MediaSession const& session) const; |
| 302 | static void handleAlternativeRequestByte(void*, u_int8_t requestByte); |
| 303 | void handleAlternativeRequestByte1(u_int8_t requestByte); |
| 304 | void constructSubsessionURL(MediaSubsession const& subsession, |
| 305 | char const*& prefix, |
| 306 | char const*& separator, |
| 307 | char const*& suffix); |
| 308 | |
| 309 | // Support for tunneling RTSP-over-HTTP: |
| 310 | Boolean setupHTTPTunneling1(); // send the HTTP "GET" |
| 311 | static void responseHandlerForHTTP_GET(RTSPClient* rtspClient, int responseCode, char* responseString); |
| 312 | void responseHandlerForHTTP_GET1(int responseCode, char* responseString); |
| 313 | Boolean setupHTTPTunneling2(); // send the HTTP "POST" |
| 314 | |
| 315 | // Support for asynchronous connections to the server: |
| 316 | static void connectionHandler(void*, int /*mask*/); |
| 317 | void connectionHandler1(); |
| 318 | |
| 319 | // Support for handling data sent back by a server: |
| 320 | static void incomingDataHandler(void*, int /*mask*/); |
| 321 | void incomingDataHandler1(); |
| 322 | void handleResponseBytes(int newBytesRead); |
| 323 | |
| 324 | // Writing/reading data over a (already set-up) connection: |
| 325 | int write(const char* data, unsigned count); |
| 326 | int read(u_int8_t* buffer, unsigned bufferSize); |
| 327 | |
| 328 | public: |
| 329 | u_int16_t desiredMaxIncomingPacketSize; |
| 330 | // If set to a value >0, then a "Blocksize:" header with this value (minus an allowance for |
| 331 | // IP, UDP, and RTP headers) will be sent with each "SETUP" request. |
| 332 | |
| 333 | protected: |
| 334 | int fVerbosityLevel; |
| 335 | unsigned fCSeq; // sequence number, used in consecutive requests |
| 336 | Authenticator fCurrentAuthenticator; |
| 337 | Boolean fAllowBasicAuthentication; |
| 338 | netAddressBits fServerAddress; |
| 339 | |
| 340 | private: |
| 341 | portNumBits fTunnelOverHTTPPortNum; |
| 342 | char* ; |
| 343 | unsigned ; |
| 344 | int fInputSocketNum, fOutputSocketNum; |
| 345 | char* fBaseURL; |
| 346 | unsigned char fTCPStreamIdCount; // used for (optional) RTP/TCP |
| 347 | char* fLastSessionId; |
| 348 | unsigned fSessionTimeoutParameter; // optionally set in response "Session:" headers |
| 349 | char* fResponseBuffer; |
| 350 | unsigned fResponseBytesAlreadySeen, fResponseBufferBytesLeft; |
| 351 | RequestQueue fRequestsAwaitingConnection, fRequestsAwaitingHTTPTunneling, fRequestsAwaitingResponse; |
| 352 | |
| 353 | // Support for tunneling RTSP-over-HTTP: |
| 354 | char fSessionCookie[33]; |
| 355 | unsigned fSessionCookieCounter; |
| 356 | Boolean fHTTPTunnelingConnectionIsPending; |
| 357 | |
| 358 | // Optional support for TLS: |
| 359 | TLSState fTLS; |
| 360 | friend class TLSState; |
| 361 | }; |
| 362 | |
| 363 | |
| 364 | #ifndef OMIT_REGISTER_HANDLING |
| 365 | ////////// HandlerServerForREGISTERCommand ///////// |
| 366 | |
| 367 | // A simple server that creates a new "RTSPClient" object whenever a "REGISTER" request arrives (specifying the "rtsp://" URL |
| 368 | // of a stream). The new "RTSPClient" object will be created with the specified URL, and passed to the provided handler function. |
| 369 | |
| 370 | typedef void onRTSPClientCreationFunc(RTSPClient* newRTSPClient, Boolean requestStreamingOverTCP); |
| 371 | |
| 372 | class HandlerServerForREGISTERCommand: public RTSPServer { |
| 373 | public: |
| 374 | static HandlerServerForREGISTERCommand* createNew(UsageEnvironment& env, onRTSPClientCreationFunc* creationFunc, |
| 375 | Port ourPort = 0, UserAuthenticationDatabase* authDatabase = NULL, |
| 376 | int verbosityLevel = 0, char const* applicationName = NULL); |
| 377 | // If ourPort.num() == 0, we'll choose the port number ourself. (Use the following function to get it.) |
| 378 | portNumBits serverPortNum() const { return ntohs(fServerPort.num()); } |
| 379 | |
| 380 | protected: |
| 381 | HandlerServerForREGISTERCommand(UsageEnvironment& env, onRTSPClientCreationFunc* creationFunc, int ourSocket, Port ourPort, |
| 382 | UserAuthenticationDatabase* authDatabase, int verbosityLevel, char const* applicationName); |
| 383 | // called only by createNew(); |
| 384 | virtual ~HandlerServerForREGISTERCommand(); |
| 385 | |
| 386 | virtual RTSPClient* createNewRTSPClient(char const* rtspURL, int verbosityLevel, char const* applicationName, |
| 387 | int socketNumToServer); |
| 388 | // This function - by default - creates a (base) "RTSPClient" object. If you want to create a subclass |
| 389 | // of "RTSPClient" instead, then subclass this class, and redefine this virtual function. |
| 390 | |
| 391 | protected: // redefined virtual functions |
| 392 | virtual char const* allowedCommandNames(); // "OPTIONS", "REGISTER", and (perhaps) "DEREGISTER" only |
| 393 | virtual Boolean weImplementREGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/, |
| 394 | char const* proxyURLSuffix, char*& responseStr); |
| 395 | // redefined to return True (for cmd=="REGISTER") |
| 396 | virtual void implementCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/, |
| 397 | char const* url, char const* urlSuffix, int socketToRemoteServer, |
| 398 | Boolean deliverViaTCP, char const* proxyURLSuffix); |
| 399 | |
| 400 | private: |
| 401 | onRTSPClientCreationFunc* fCreationFunc; |
| 402 | int fVerbosityLevel; |
| 403 | char* fApplicationName; |
| 404 | }; |
| 405 | #endif |
| 406 | |
| 407 | #endif |
| 408 | |