📄 rtspclient.cpp
字号:
/**********This library is free software; you can redistribute it and/or modify it underthe terms of the GNU Lesser General Public License as published by theFree Software Foundation; either version 2.1 of the License, or (at youroption) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)This library is distributed in the hope that it will be useful, but WITHOUTANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESSFOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License formore details.You should have received a copy of the GNU Lesser General Public Licensealong with this library; if not, write to the Free Software Foundation, Inc.,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA**********/// "liveMedia"// Copyright (c) 1996-2010 Live Networks, Inc. All rights reserved.// A generic RTSP client// Implementation#include "RTSPClient.hh"#include "RTSPCommon.hh"#include "Base64.hh"#include "Locale.hh"#include <GroupsockHelper.hh>#include "our_md5.h"////////// RTSPClient implementation //////////RTSPClient* RTSPClient::createNew(UsageEnvironment& env, char const* rtspURL, int verbosityLevel, char const* applicationName, portNumBits tunnelOverHTTPPortNum) { return new RTSPClient(env, rtspURL, verbosityLevel, applicationName, tunnelOverHTTPPortNum);}unsigned RTSPClient::sendDescribeCommand(responseHandler* responseHandler, Authenticator* authenticator) { if (authenticator != NULL) fCurrentAuthenticator = *authenticator; return sendRequest(new RequestRecord(++fCSeq, "DESCRIBE", responseHandler));}unsigned RTSPClient::sendOptionsCommand(responseHandler* responseHandler, Authenticator* authenticator) { if (authenticator != NULL) fCurrentAuthenticator = *authenticator; return sendRequest(new RequestRecord(++fCSeq, "OPTIONS", responseHandler));}unsigned RTSPClient::sendAnnounceCommand(char const* sdpDescription, responseHandler* responseHandler, Authenticator* authenticator) { if (authenticator != NULL) fCurrentAuthenticator = *authenticator; return sendRequest(new RequestRecord(++fCSeq, "ANNOUNCE", responseHandler, NULL, NULL, False, 0.0, 0.0, 0.0, sdpDescription));}unsigned RTSPClient::sendSetupCommand(MediaSubsession& subsession, responseHandler* responseHandler, Boolean streamOutgoing, Boolean streamUsingTCP, Boolean forceMulticastOnUnspecified, Authenticator* authenticator) { if (fTunnelOverHTTPPortNum != 0) streamUsingTCP = True; // RTSP-over-HTTP tunneling uses TCP (by definition) if (authenticator != NULL) fCurrentAuthenticator = *authenticator; u_int32_t booleanFlags = 0; if (streamUsingTCP) booleanFlags |= 0x1; if (streamOutgoing) booleanFlags |= 0x2; if (forceMulticastOnUnspecified) booleanFlags |= 0x4; return sendRequest(new RequestRecord(++fCSeq, "SETUP", responseHandler, NULL, &subsession, booleanFlags));}unsigned RTSPClient::sendPlayCommand(MediaSession& session, responseHandler* responseHandler, double start, double end, float scale, Authenticator* authenticator) { if (authenticator != NULL) fCurrentAuthenticator = *authenticator; return sendRequest(new RequestRecord(++fCSeq, "PLAY", responseHandler, &session, NULL, 0, start, end, scale));}unsigned RTSPClient::sendPlayCommand(MediaSubsession& subsession, responseHandler* responseHandler, double start, double end, float scale, Authenticator* authenticator) { if (authenticator != NULL) fCurrentAuthenticator = *authenticator; return sendRequest(new RequestRecord(++fCSeq, "PLAY", responseHandler, NULL, &subsession, 0, start, end, scale));}unsigned RTSPClient::sendPauseCommand(MediaSession& session, responseHandler* responseHandler, Authenticator* authenticator) { if (authenticator != NULL) fCurrentAuthenticator = *authenticator; return sendRequest(new RequestRecord(++fCSeq, "PAUSE", responseHandler, &session));}unsigned RTSPClient::sendPauseCommand(MediaSubsession& subsession, responseHandler* responseHandler, Authenticator* authenticator) { if (authenticator != NULL) fCurrentAuthenticator = *authenticator; return sendRequest(new RequestRecord(++fCSeq, "PAUSE", responseHandler, NULL, &subsession));}unsigned RTSPClient::sendRecordCommand(MediaSession& session, responseHandler* responseHandler, Authenticator* authenticator) { if (authenticator != NULL) fCurrentAuthenticator = *authenticator; return sendRequest(new RequestRecord(++fCSeq, "RECORD", responseHandler, &session));}unsigned RTSPClient::sendRecordCommand(MediaSubsession& subsession, responseHandler* responseHandler, Authenticator* authenticator) { if (authenticator != NULL) fCurrentAuthenticator = *authenticator; return sendRequest(new RequestRecord(++fCSeq, "RECORD", responseHandler, NULL, &subsession));}unsigned RTSPClient::sendTeardownCommand(MediaSession& session, responseHandler* responseHandler, Authenticator* authenticator) { if (authenticator != NULL) fCurrentAuthenticator = *authenticator; return sendRequest(new RequestRecord(++fCSeq, "TEARDOWN", responseHandler, &session));}unsigned RTSPClient::sendTeardownCommand(MediaSubsession& subsession, responseHandler* responseHandler, Authenticator* authenticator) { if (authenticator != NULL) fCurrentAuthenticator = *authenticator; return sendRequest(new RequestRecord(++fCSeq, "TEARDOWN", responseHandler, NULL, &subsession));}unsigned RTSPClient::sendSetParameterCommand(MediaSession& session, responseHandler* responseHandler, char const* parameterName, char const* parameterValue, Authenticator* authenticator) { if (authenticator != NULL) fCurrentAuthenticator = *authenticator; char* paramString = new char[strlen(parameterName) + strlen(parameterValue) + 10]; sprintf(paramString, "%s: %s\r\n", parameterName, parameterValue); unsigned result = sendRequest(new RequestRecord(++fCSeq, "SET_PARAMETER", responseHandler, &session, NULL, False, 0.0, 0.0, 0.0, paramString)); delete[] paramString; return result;}unsigned RTSPClient::sendGetParameterCommand(MediaSession& session, responseHandler* responseHandler, char const* parameterName, Authenticator* authenticator) { if (authenticator != NULL) fCurrentAuthenticator = *authenticator; // We assume that: // parameterName is NULL means: Send no body in the request. // parameterName is "" means: Send only \r\n in the request body. // parameterName is non-empty means: Send "<parameterName>\r\n" as the request body. unsigned parameterNameLen = parameterName == NULL ? 0 : strlen(parameterName); char* paramString = new char[parameterNameLen + 3]; // the 3 is for \r\n + the '\0' byte if (parameterName == NULL) { paramString[0] = '\0'; } else { sprintf(paramString, "%s\r\n", parameterName); } unsigned result = sendRequest(new RequestRecord(++fCSeq, "GET_PARAMETER", responseHandler, &session, NULL, False, 0.0, 0.0, 0.0, paramString)); delete[] paramString; return result;}Boolean RTSPClient::changeResponseHandler(unsigned cseq, responseHandler* newResponseHandler) { // Look for the matching request record in each of our 'pending requests' queues: RequestRecord* request; if ((request = fRequestsAwaitingConnection.findByCSeq(cseq)) != NULL || (request = fRequestsAwaitingHTTPTunneling.findByCSeq(cseq)) != NULL || (request = fRequestsAwaitingResponse.findByCSeq(cseq)) != NULL) { request->handler() = newResponseHandler; return True; } return False;}Boolean RTSPClient::lookupByName(UsageEnvironment& env, char const* instanceName, RTSPClient*& resultClient) { resultClient = NULL; // unless we succeed Medium* medium; if (!Medium::lookupByName(env, instanceName, medium)) return False; if (!medium->isRTSPClient()) { env.setResultMsg(instanceName, " is not a RTSP client"); return False; } resultClient = (RTSPClient*)medium; return True;}Boolean RTSPClient::parseRTSPURL(UsageEnvironment& env, char const* url, NetAddress& address, portNumBits& portNum, char const** urlSuffix) { do { // Parse the URL as "rtsp://<address>:<port>/<etc>" // (with ":<port>" and "/<etc>" optional) // Also, skip over any "<username>[:<password>]@" preceding <address> char const* prefix = "rtsp://"; unsigned const prefixLength = 7; if (_strncasecmp(url, prefix, prefixLength) != 0) { env.setResultMsg("URL is not of the form \"", prefix, "\""); break; } unsigned const parseBufferSize = 100; char parseBuffer[parseBufferSize]; char const* from = &url[prefixLength]; // Skip over any "<username>[:<password>]@" // (Note that this code fails if <password> contains '@' or '/', but // given that these characters can also appear in <etc>, there seems to // be no way of unambiguously parsing that situation.) char const* from1 = from; while (*from1 != '\0' && *from1 != '/') { if (*from1 == '@') { from = ++from1; break; } ++from1; } char* to = &parseBuffer[0]; unsigned i; for (i = 0; i < parseBufferSize; ++i) { if (*from == '\0' || *from == ':' || *from == '/') { // We've completed parsing the address *to = '\0'; break; } *to++ = *from++; } if (i == parseBufferSize) { env.setResultMsg("URL is too long"); break; } NetAddressList addresses(parseBuffer); if (addresses.numAddresses() == 0) { env.setResultMsg("Failed to find network address for \"", parseBuffer, "\""); break; } address = *(addresses.firstAddress()); portNum = 554; // default value char nextChar = *from; if (nextChar == ':') { int portNumInt; if (sscanf(++from, "%d", &portNumInt) != 1) { env.setResultMsg("No port number follows ':'"); break; } if (portNumInt < 1 || portNumInt > 65535) { env.setResultMsg("Bad port number"); break; } portNum = (portNumBits)portNumInt; while (*from >= '0' && *from <= '9') ++from; // skip over port number } // The remainder of the URL is the suffix: if (urlSuffix != NULL) *urlSuffix = from; return True; } while (0); return False;}Boolean RTSPClient::parseRTSPURLUsernamePassword(char const* url, char*& username, char*& password) { username = password = NULL; // by default do { // Parse the URL as "rtsp://<username>[:<password>]@<whatever>" char const* prefix = "rtsp://"; unsigned const prefixLength = 7; if (_strncasecmp(url, prefix, prefixLength) != 0) break; // Look for the ':' and '@': unsigned usernameIndex = prefixLength; unsigned colonIndex = 0, atIndex = 0; for (unsigned i = usernameIndex; url[i] != '\0' && url[i] != '/'; ++i) { if (url[i] == ':' && colonIndex == 0) { colonIndex = i; } else if (url[i] == '@') { atIndex = i; break; // we're done } } if (atIndex == 0) break; // no '@' found char* urlCopy = strDup(url); urlCopy[atIndex] = '\0'; if (colonIndex > 0) { urlCopy[colonIndex] = '\0'; password = strDup(&urlCopy[colonIndex+1]); } else { password = strDup(""); } username = strDup(&urlCopy[usernameIndex]); delete[] urlCopy; return True; } while (0); return False;}void RTSPClient::setUserAgentString(char const* userAgentName) { if (userAgentName == NULL) return; // Change the existing user agent header string: char const* const formatStr = "User-Agent: %s\r\n"; unsigned const headerSize = strlen(formatStr) + strlen(userAgentName); delete[] fUserAgentHeaderStr; fUserAgentHeaderStr = new char[headerSize]; sprintf(fUserAgentHeaderStr, formatStr, userAgentName); fUserAgentHeaderStrLen = strlen(fUserAgentHeaderStr);}unsigned RTSPClient::responseBufferSize = 20000; // default value; you can reassign this in your application if you need toRTSPClient::RTSPClient(UsageEnvironment& env, char const* rtspURL, int verbosityLevel, char const* applicationName, portNumBits tunnelOverHTTPPortNum) : Medium(env), fVerbosityLevel(verbosityLevel), fTunnelOverHTTPPortNum(tunnelOverHTTPPortNum), fUserAgentHeaderStr(NULL), fUserAgentHeaderStrLen(0), fInputSocketNum(-1), fOutputSocketNum(-1), fServerAddress(0), fCSeq(1), fBaseURL(NULL), fTCPStreamIdCount(0), fLastSessionId(NULL), fSessionTimeoutParameter(0), fSessionCookieCounter(0), fHTTPTunnelingConnectionIsPending(False) { setBaseURL(rtspURL); fResponseBuffer = new char[responseBufferSize+1]; resetResponseBuffer(); // Set the "User-Agent:" header to use in each request: char const* const libName = "LIVE555 Streaming Media v"; char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING; char const* libPrefix; char const* libSuffix; if (applicationName == NULL || applicationName[0] == '\0') { applicationName = libPrefix = libSuffix = ""; } else { libPrefix = " ("; libSuffix = ")"; } unsigned userAgentNameSize = strlen(applicationName) + strlen(libPrefix) + strlen(libName) + strlen(libVersionStr) + strlen(libSuffix) + 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -