1/**********
2This library is free software; you can redistribute it and/or modify it under
3the terms of the GNU Lesser General Public License as published by the
4Free Software Foundation; either version 3 of the License, or (at your
5option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
6
7This library is distributed in the hope that it will be useful, but WITHOUT
8ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
10more details.
11
12You should have received a copy of the GNU Lesser General Public License
13along with this library; if not, write to the Free Software Foundation, Inc.,
1451 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 subclass of "ServerMediaSession" that can be used to create a (unicast) RTSP servers that acts as a 'proxy' for
19// another (unicast or multicast) RTSP/RTP stream.
20// C++ header
21
22#ifndef _PROXY_SERVER_MEDIA_SESSION_HH
23#define _PROXY_SERVER_MEDIA_SESSION_HH
24
25#ifndef _SERVER_MEDIA_SESSION_HH
26#include "ServerMediaSession.hh"
27#endif
28#ifndef _MEDIA_SESSION_HH
29#include "MediaSession.hh"
30#endif
31#ifndef _RTSP_CLIENT_HH
32#include "RTSPClient.hh"
33#endif
34#ifndef _MEDIA_TRANSCODING_TABLE_HH
35#include "MediaTranscodingTable.hh"
36#endif
37
38// A subclass of "RTSPClient", used to refer to the particular "ProxyServerMediaSession" object being used.
39// It is used only within the implementation of "ProxyServerMediaSession", but is defined here, in case developers wish to
40// subclass it.
41
42class ProxyRTSPClient: public RTSPClient {
43public:
44 ProxyRTSPClient(class ProxyServerMediaSession& ourServerMediaSession, char const* rtspURL,
45 char const* username, char const* password,
46 portNumBits tunnelOverHTTPPortNum, int verbosityLevel, int socketNumToServer);
47 virtual ~ProxyRTSPClient();
48
49 void continueAfterDESCRIBE(char const* sdpDescription);
50 void continueAfterLivenessCommand(int resultCode, Boolean serverSupportsGetParameter);
51 void continueAfterSETUP(int resultCode);
52 void continueAfterPLAY(int resultCode);
53 void scheduleReset();
54
55private:
56 void reset();
57 int connectToServer(int socketNum, portNumBits remotePortNum);
58
59 Authenticator* auth() { return fOurAuthenticator; }
60
61 void scheduleLivenessCommand();
62 static void sendLivenessCommand(void* clientData);
63 void doReset();
64 static void doReset(void* clientData);
65
66 void scheduleDESCRIBECommand();
67 static void sendDESCRIBE(void* clientData);
68
69 static void subsessionTimeout(void* clientData);
70 void handleSubsessionTimeout();
71
72private:
73 friend class ProxyServerMediaSession;
74 friend class ProxyServerMediaSubsession;
75 ProxyServerMediaSession& fOurServerMediaSession;
76 char* fOurURL;
77 Authenticator* fOurAuthenticator;
78 Boolean fStreamRTPOverTCP;
79 class ProxyServerMediaSubsession *fSetupQueueHead, *fSetupQueueTail;
80 unsigned fNumSetupsDone;
81 unsigned fNextDESCRIBEDelay; // in seconds
82 Boolean fServerSupportsGetParameter, fLastCommandWasPLAY, fDoneDESCRIBE;
83 TaskToken fLivenessCommandTask, fDESCRIBECommandTask, fSubsessionTimerTask, fResetTask;
84};
85
86
87typedef ProxyRTSPClient*
88createNewProxyRTSPClientFunc(ProxyServerMediaSession& ourServerMediaSession,
89 char const* rtspURL,
90 char const* username, char const* password,
91 portNumBits tunnelOverHTTPPortNum, int verbosityLevel,
92 int socketNumToServer);
93ProxyRTSPClient*
94defaultCreateNewProxyRTSPClientFunc(ProxyServerMediaSession& ourServerMediaSession,
95 char const* rtspURL,
96 char const* username, char const* password,
97 portNumBits tunnelOverHTTPPortNum, int verbosityLevel,
98 int socketNumToServer);
99
100class ProxyServerMediaSession: public ServerMediaSession {
101public:
102 static ProxyServerMediaSession* createNew(UsageEnvironment& env,
103 GenericMediaServer* ourMediaServer, // Note: We can be used by just one server
104 char const* inputStreamURL, // the "rtsp://" URL of the stream we'll be proxying
105 char const* streamName = NULL,
106 char const* username = NULL, char const* password = NULL,
107 portNumBits tunnelOverHTTPPortNum = 0,
108 // for streaming the *proxied* (i.e., back-end) stream
109 int verbosityLevel = 0,
110 int socketNumToServer = -1,
111 MediaTranscodingTable* transcodingTable = NULL);
112 // Hack: "tunnelOverHTTPPortNum" == 0xFFFF (i.e., all-ones) means: Stream RTP/RTCP-over-TCP, but *not* using HTTP
113 // "verbosityLevel" == 1 means display basic proxy setup info; "verbosityLevel" == 2 means display RTSP client protocol also.
114 // If "socketNumToServer" is >= 0, then it is the socket number of an already-existing TCP connection to the server.
115 // (In this case, "inputStreamURL" must point to the socket's endpoint, so that it can be accessed via the socket.)
116
117 virtual ~ProxyServerMediaSession();
118
119 char const* url() const;
120
121 char describeCompletedFlag;
122 // initialized to 0; set to 1 when the back-end "DESCRIBE" completes.
123 // (This can be used as a 'watch variable' in "doEventLoop()".)
124 Boolean describeCompletedSuccessfully() const { return fClientMediaSession != NULL; }
125 // This can be used - along with "describeCompletdFlag" - to check whether the back-end "DESCRIBE" completed *successfully*.
126
127protected:
128 ProxyServerMediaSession(UsageEnvironment& env, GenericMediaServer* ourMediaServer,
129 char const* inputStreamURL, char const* streamName,
130 char const* username, char const* password,
131 portNumBits tunnelOverHTTPPortNum, int verbosityLevel,
132 int socketNumToServer,
133 MediaTranscodingTable* transcodingTable,
134 createNewProxyRTSPClientFunc* ourCreateNewProxyRTSPClientFunc
135 = defaultCreateNewProxyRTSPClientFunc,
136 portNumBits initialPortNum = 6970,
137 Boolean multiplexRTCPWithRTP = False);
138
139 // If you subclass "ProxyRTSPClient", then you will also need to define your own function
140 // - with signature "createNewProxyRTSPClientFunc" (see above) - that creates a new object
141 // of this subclass. You should also subclass "ProxyServerMediaSession" and, in your
142 // subclass's constructor, initialize the parent class (i.e., "ProxyServerMediaSession")
143 // constructor by passing your new function as the "ourCreateNewProxyRTSPClientFunc"
144 // parameter.
145
146 // Subclasses may redefine the following functions, if they want "ProxyServerSubsession"s
147 // to create subclassed "Groupsock" and/or "RTCPInstance" objects:
148 virtual Groupsock* createGroupsock(struct in_addr const& addr, Port port);
149 virtual RTCPInstance* createRTCP(Groupsock* RTCPgs, unsigned totSessionBW, /* in kbps */
150 unsigned char const* cname, RTPSink* sink);
151
152 virtual Boolean allowProxyingForSubsession(MediaSubsession const& mss);
153 // By default, this function always returns True. However, a subclass may redefine this
154 // if it wishes to restrict which subsessions of a stream get proxied - e.g., if it wishes
155 // to proxy only video tracks, but not audio (or other) tracks.
156
157protected:
158 GenericMediaServer* fOurMediaServer;
159 ProxyRTSPClient* fProxyRTSPClient;
160 MediaSession* fClientMediaSession;
161
162private:
163 friend class ProxyRTSPClient;
164 friend class ProxyServerMediaSubsession;
165 void continueAfterDESCRIBE(char const* sdpDescription);
166 void resetDESCRIBEState(); // undoes what was done by "contineAfterDESCRIBE()"
167
168private:
169 int fVerbosityLevel;
170 class PresentationTimeSessionNormalizer* fPresentationTimeSessionNormalizer;
171 createNewProxyRTSPClientFunc* fCreateNewProxyRTSPClientFunc;
172 MediaTranscodingTable* fTranscodingTable;
173 portNumBits fInitialPortNum;
174 Boolean fMultiplexRTCPWithRTP;
175};
176
177
178////////// PresentationTimeSessionNormalizer and PresentationTimeSubsessionNormalizer definitions //////////
179
180// The following two classes are used by proxies to convert incoming streams' presentation times into wall-clock-aligned
181// presentation times that are suitable for our "RTPSink"s (for the corresponding outgoing streams).
182// (For multi-subsession (i.e., audio+video) sessions, the outgoing streams' presentation times retain the same relative
183// separation as those of the incoming streams.)
184
185class PresentationTimeSubsessionNormalizer: public FramedFilter {
186public:
187 void setRTPSink(RTPSink* rtpSink) { fRTPSink = rtpSink; }
188
189private:
190 friend class PresentationTimeSessionNormalizer;
191 PresentationTimeSubsessionNormalizer(PresentationTimeSessionNormalizer& parent, FramedSource* inputSource, RTPSource* rtpSource,
192 char const* codecName, PresentationTimeSubsessionNormalizer* next);
193 // called only from within "PresentationTimeSessionNormalizer"
194 virtual ~PresentationTimeSubsessionNormalizer();
195
196 static void afterGettingFrame(void* clientData, unsigned frameSize,
197 unsigned numTruncatedBytes,
198 struct timeval presentationTime,
199 unsigned durationInMicroseconds);
200 void afterGettingFrame(unsigned frameSize,
201 unsigned numTruncatedBytes,
202 struct timeval presentationTime,
203 unsigned durationInMicroseconds);
204
205private: // redefined virtual functions:
206 virtual void doGetNextFrame();
207
208private:
209 PresentationTimeSessionNormalizer& fParent;
210 RTPSource* fRTPSource;
211 RTPSink* fRTPSink;
212 char const* fCodecName;
213 PresentationTimeSubsessionNormalizer* fNext;
214};
215
216class PresentationTimeSessionNormalizer: public Medium {
217public:
218 PresentationTimeSessionNormalizer(UsageEnvironment& env);
219 virtual ~PresentationTimeSessionNormalizer();
220
221 PresentationTimeSubsessionNormalizer*
222 createNewPresentationTimeSubsessionNormalizer(FramedSource* inputSource, RTPSource* rtpSource, char const* codecName);
223
224private: // called only from within "~PresentationTimeSubsessionNormalizer":
225 friend class PresentationTimeSubsessionNormalizer;
226 void normalizePresentationTime(PresentationTimeSubsessionNormalizer* ssNormalizer,
227 struct timeval& toPT, struct timeval const& fromPT);
228 void removePresentationTimeSubsessionNormalizer(PresentationTimeSubsessionNormalizer* ssNormalizer);
229
230private:
231 PresentationTimeSubsessionNormalizer* fSubsessionNormalizers;
232 PresentationTimeSubsessionNormalizer* fMasterSSNormalizer; // used for subsessions that have been RTCP-synced
233
234 struct timeval fPTAdjustment; // Added to (RTCP-synced) subsession presentation times to 'normalize' them with wall-clock time.
235};
236
237#endif
238