RTSPClient.hh 22 KB

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