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 data structure that represents a session that consists of
19// potentially multiple (audio and/or video) sub-sessions
20// (This data structure is used for media *receivers* - i.e., clients.
21// For media streamers, use "ServerMediaSession" instead.)
22// C++ header
23
24/* NOTE: To support receiving your own custom RTP payload format, you must first define a new
25 subclass of "MultiFramedRTPSource" (or "BasicUDPSource") that implements it.
26 Then define your own subclass of "MediaSession" and "MediaSubsession", as follows:
27 - In your subclass of "MediaSession" (named, for example, "myMediaSession"):
28 - Define and implement your own static member function
29 static myMediaSession* createNew(UsageEnvironment& env, char const* sdpDescription);
30 and call this - instead of "MediaSession::createNew()" - in your application,
31 when you create a new "MediaSession" object.
32 - Reimplement the "createNewMediaSubsession()" virtual function, as follows:
33 MediaSubsession* myMediaSession::createNewMediaSubsession() { return new myMediaSubsession(*this); }
34 - In your subclass of "MediaSubsession" (named, for example, "myMediaSubsession"):
35 - Reimplement the "createSourceObjects()" virtual function, perhaps similar to this:
36 Boolean myMediaSubsession::createSourceObjects(int useSpecialRTPoffset) {
37 if (strcmp(fCodecName, "X-MY-RTP-PAYLOAD-FORMAT") == 0) {
38 // This subsession uses our custom RTP payload format:
39 fReadSource = fRTPSource = myRTPPayloadFormatRTPSource::createNew( <parameters> );
40 return True;
41 } else {
42 // This subsession uses some other RTP payload format - perhaps one that we already implement:
43 return ::createSourceObjects(useSpecialRTPoffset);
44 }
45 }
46*/
47
48#ifndef _MEDIA_SESSION_HH
49#define _MEDIA_SESSION_HH
50
51#ifndef _RTCP_HH
52#include "RTCP.hh"
53#endif
54#ifndef _FRAMED_FILTER_HH
55#include "FramedFilter.hh"
56#endif
57
58class MediaSubsession; // forward
59
60class MediaSession: public Medium {
61public:
62 static MediaSession* createNew(UsageEnvironment& env,
63 char const* sdpDescription);
64
65 static Boolean lookupByName(UsageEnvironment& env, char const* sourceName,
66 MediaSession*& resultSession);
67
68 Boolean hasSubsessions() const { return fSubsessionsHead != NULL; }
69
70 char* connectionEndpointName() const { return fConnectionEndpointName; }
71 char const* CNAME() const { return fCNAME; }
72 struct in_addr const& sourceFilterAddr() const { return fSourceFilterAddr; }
73 float& scale() { return fScale; }
74 float& speed() { return fSpeed; }
75 char* mediaSessionType() const { return fMediaSessionType; }
76 char* sessionName() const { return fSessionName; }
77 char* sessionDescription() const { return fSessionDescription; }
78 char const* controlPath() const { return fControlPath; }
79
80 double& playStartTime() { return fMaxPlayStartTime; }
81 double& playEndTime() { return fMaxPlayEndTime; }
82 char* absStartTime() const;
83 char* absEndTime() const;
84 // Used only to set the local fields:
85 char*& _absStartTime() { return fAbsStartTime; }
86 char*& _absEndTime() { return fAbsEndTime; }
87
88 Boolean initiateByMediaType(char const* mimeType,
89 MediaSubsession*& resultSubsession,
90 int useSpecialRTPoffset = -1);
91 // Initiates the first subsession with the specified MIME type
92 // Returns the resulting subsession, or 'multi source' (not both)
93
94protected: // redefined virtual functions
95 virtual Boolean isMediaSession() const;
96
97protected:
98 MediaSession(UsageEnvironment& env);
99 // called only by createNew();
100 virtual ~MediaSession();
101
102 virtual MediaSubsession* createNewMediaSubsession();
103
104 Boolean initializeWithSDP(char const* sdpDescription);
105 Boolean parseSDPLine(char const* input, char const*& nextLine);
106 Boolean parseSDPLine_s(char const* sdpLine);
107 Boolean parseSDPLine_i(char const* sdpLine);
108 Boolean parseSDPLine_c(char const* sdpLine);
109 Boolean parseSDPAttribute_type(char const* sdpLine);
110 Boolean parseSDPAttribute_control(char const* sdpLine);
111 Boolean parseSDPAttribute_range(char const* sdpLine);
112 Boolean parseSDPAttribute_source_filter(char const* sdpLine);
113
114 static char* lookupPayloadFormat(unsigned char rtpPayloadType,
115 unsigned& rtpTimestampFrequency,
116 unsigned& numChannels);
117 static unsigned guessRTPTimestampFrequency(char const* mediumName,
118 char const* codecName);
119
120protected:
121 friend class MediaSubsessionIterator;
122 char* fCNAME; // used for RTCP
123
124 // Linkage fields:
125 MediaSubsession* fSubsessionsHead;
126 MediaSubsession* fSubsessionsTail;
127
128 // Fields set from a SDP description:
129 char* fConnectionEndpointName;
130 double fMaxPlayStartTime;
131 double fMaxPlayEndTime;
132 char* fAbsStartTime;
133 char* fAbsEndTime;
134 struct in_addr fSourceFilterAddr; // used for SSM
135 float fScale; // set from a RTSP "Scale:" header
136 float fSpeed;
137 char* fMediaSessionType; // holds a=type value
138 char* fSessionName; // holds s=<session name> value
139 char* fSessionDescription; // holds i=<session description> value
140 char* fControlPath; // holds optional a=control: string
141};
142
143
144class MediaSubsessionIterator {
145public:
146 MediaSubsessionIterator(MediaSession const& session);
147 virtual ~MediaSubsessionIterator();
148
149 MediaSubsession* next(); // NULL if none
150 void reset();
151
152private:
153 MediaSession const& fOurSession;
154 MediaSubsession* fNextPtr;
155};
156
157
158class MediaSubsession {
159public:
160 MediaSession& parentSession() { return fParent; }
161 MediaSession const& parentSession() const { return fParent; }
162
163 unsigned short clientPortNum() const { return fClientPortNum; }
164 unsigned char rtpPayloadFormat() const { return fRTPPayloadFormat; }
165 char const* savedSDPLines() const { return fSavedSDPLines; }
166 char const* mediumName() const { return fMediumName; }
167 char const* codecName() const { return fCodecName; }
168 char const* protocolName() const { return fProtocolName; }
169 char const* controlPath() const { return fControlPath; }
170 Boolean isSSM() const { return fSourceFilterAddr.s_addr != 0; }
171
172 unsigned short videoWidth() const { return fVideoWidth; }
173 unsigned short videoHeight() const { return fVideoHeight; }
174 unsigned videoFPS() const { return fVideoFPS; }
175 unsigned numChannels() const { return fNumChannels; }
176 float& scale() { return fScale; }
177 float& speed() { return fSpeed; }
178
179 RTPSource* rtpSource() { return fRTPSource; }
180 RTCPInstance* rtcpInstance() { return fRTCPInstance; }
181 unsigned rtpTimestampFrequency() const { return fRTPTimestampFrequency; }
182 Boolean rtcpIsMuxed() const { return fMultiplexRTCPWithRTP; }
183 FramedSource* readSource() { return fReadSource; }
184 // This is the source that client sinks read from. It is usually
185 // (but not necessarily) the same as "rtpSource()"
186 void addFilter(FramedFilter* filter);
187 // Changes "readSource()" to "filter" (which must have just been created with "readSource()" as its input)
188
189 double playStartTime() const;
190 double playEndTime() const;
191 char* absStartTime() const;
192 char* absEndTime() const;
193 // Used only to set the local fields:
194 double& _playStartTime() { return fPlayStartTime; }
195 double& _playEndTime() { return fPlayEndTime; }
196 char*& _absStartTime() { return fAbsStartTime; }
197 char*& _absEndTime() { return fAbsEndTime; }
198
199 Boolean initiate(int useSpecialRTPoffset = -1);
200 // Creates a "RTPSource" for this subsession. (Has no effect if it's
201 // already been created.) Returns True iff this succeeds.
202 void deInitiate(); // Destroys any previously created RTPSource
203 Boolean setClientPortNum(unsigned short portNum);
204 // Sets the preferred client port number that any "RTPSource" for
205 // this subsession would use. (By default, the client port number
206 // is gotten from the original SDP description, or - if the SDP
207 // description does not specfy a client port number - an ephemeral
208 // (even) port number is chosen.) This routine must *not* be
209 // called after initiate().
210 void receiveRawMP3ADUs() { fReceiveRawMP3ADUs = True; } // optional hack for audio/MPA-ROBUST; must not be called after initiate()
211 void receiveRawJPEGFrames() { fReceiveRawJPEGFrames = True; } // optional hack for video/JPEG; must not be called after initiate()
212 char*& connectionEndpointName() { return fConnectionEndpointName; }
213 char const* connectionEndpointName() const {
214 return fConnectionEndpointName;
215 }
216
217 // 'Bandwidth' parameter, set in the "b=" SDP line:
218 unsigned bandwidth() const { return fBandwidth; }
219
220 // General SDP attribute accessor functions:
221 char const* attrVal_str(char const* attrName) const;
222 // returns "" if attribute doesn't exist (and has no default value), or is not a string
223 char const* attrVal_strToLower(char const* attrName) const;
224 // returns "" if attribute doesn't exist (and has no default value), or is not a string
225 unsigned attrVal_int(char const* attrName) const;
226 // also returns 0 if attribute doesn't exist (and has no default value)
227 unsigned attrVal_unsigned(char const* attrName) const { return (unsigned)attrVal_int(attrName); }
228 Boolean attrVal_bool(char const* attrName) const { return attrVal_int(attrName) != 0; }
229
230 // Old, now-deprecated SDP attribute accessor functions, kept here for backwards-compatibility:
231 char const* fmtp_config() const;
232 char const* fmtp_configuration() const { return fmtp_config(); }
233 char const* fmtp_spropparametersets() const { return attrVal_str("sprop-parameter-sets"); }
234 char const* fmtp_spropvps() const { return attrVal_str("sprop-vps"); }
235 char const* fmtp_spropsps() const { return attrVal_str("sprop-sps"); }
236 char const* fmtp_sproppps() const { return attrVal_str("sprop-pps"); }
237
238 netAddressBits connectionEndpointAddress() const;
239 // Converts "fConnectionEndpointName" to an address (or 0 if unknown)
240 void setDestinations(netAddressBits defaultDestAddress);
241 // Uses "fConnectionEndpointName" and "serverPortNum" to set
242 // the destination address and port of the RTP and RTCP objects.
243 // This is typically called by RTSP clients after doing "SETUP".
244
245 char const* sessionId() const { return fSessionId; }
246 void setSessionId(char const* sessionId);
247
248 // Public fields that external callers can use to keep state.
249 // (They are responsible for all storage management on these fields)
250 unsigned short serverPortNum; // in host byte order (used by RTSP)
251 unsigned char rtpChannelId, rtcpChannelId; // used by RTSP (for RTP/TCP)
252 MediaSink* sink; // callers can use this to keep track of who's playing us
253 void* miscPtr; // callers can use this for whatever they want
254
255 // Parameters set from a RTSP "RTP-Info:" header:
256 struct {
257 u_int16_t seqNum;
258 u_int32_t timestamp;
259 Boolean infoIsNew; // not part of the RTSP header; instead, set whenever this struct is filled in
260 } rtpInfo;
261
262 double getNormalPlayTime(struct timeval const& presentationTime);
263 // Computes the stream's "Normal Play Time" (NPT) from the given "presentationTime".
264 // (For the definition of "Normal Play Time", see RFC 2326, section 3.6.)
265 // This function is useful only if the "rtpInfo" structure was previously filled in
266 // (e.g., by a "RTP-Info:" header in a RTSP response).
267 // Also, for this function to work properly, the RTP stream's presentation times must (eventually) be
268 // synchronized via RTCP.
269 // (Note: If this function returns a negative number, then the result should be ignored by the caller.)
270
271protected:
272 friend class MediaSession;
273 friend class MediaSubsessionIterator;
274 MediaSubsession(MediaSession& parent);
275 virtual ~MediaSubsession();
276
277 UsageEnvironment& env() { return fParent.envir(); }
278 void setNext(MediaSubsession* next) { fNext = next; }
279
280 void setAttribute(char const* name, char const* value = NULL, Boolean valueIsHexadecimal = False);
281
282 Boolean parseSDPLine_c(char const* sdpLine);
283 Boolean parseSDPLine_b(char const* sdpLine);
284 Boolean parseSDPAttribute_rtpmap(char const* sdpLine);
285 Boolean parseSDPAttribute_rtcpmux(char const* sdpLine);
286 Boolean parseSDPAttribute_control(char const* sdpLine);
287 Boolean parseSDPAttribute_range(char const* sdpLine);
288 Boolean parseSDPAttribute_fmtp(char const* sdpLine);
289 Boolean parseSDPAttribute_source_filter(char const* sdpLine);
290 Boolean parseSDPAttribute_x_dimensions(char const* sdpLine);
291 Boolean parseSDPAttribute_framerate(char const* sdpLine);
292
293 virtual Boolean createSourceObjects(int useSpecialRTPoffset);
294 // create "fRTPSource" and "fReadSource" member objects, after we've been initialized via SDP
295
296protected:
297 // Linkage fields:
298 MediaSession& fParent;
299 MediaSubsession* fNext;
300
301 // Fields set from a SDP description:
302 char* fConnectionEndpointName; // may also be set by RTSP SETUP response
303 unsigned short fClientPortNum; // in host byte order
304 // This field is also set by initiate()
305 unsigned char fRTPPayloadFormat;
306 char* fSavedSDPLines;
307 char* fMediumName;
308 char* fCodecName;
309 char* fProtocolName;
310 unsigned fRTPTimestampFrequency;
311 Boolean fMultiplexRTCPWithRTP;
312 char* fControlPath; // holds optional a=control: string
313 struct in_addr fSourceFilterAddr; // used for SSM
314 unsigned fBandwidth; // in kilobits-per-second, from b= line
315
316 double fPlayStartTime;
317 double fPlayEndTime;
318 char* fAbsStartTime;
319 char* fAbsEndTime;
320 unsigned short fVideoWidth, fVideoHeight;
321 // screen dimensions (set by an optional a=x-dimensions: <w>,<h> line)
322 unsigned fVideoFPS;
323 // frame rate (set by an optional "a=framerate: <fps>" or "a=x-framerate: <fps>" line)
324 unsigned fNumChannels;
325 // optionally set by "a=rtpmap:" lines for audio sessions. Default: 1
326 float fScale; // set from a RTSP "Scale:" header
327 float fSpeed;
328 double fNPT_PTS_Offset; // set by "getNormalPlayTime()"; add this to a PTS to get NPT
329 HashTable* fAttributeTable; // for "a=fmtp:" attributes. (Later an array by payload type #####)
330
331 // Fields set or used by initiate():
332 Groupsock* fRTPSocket; Groupsock* fRTCPSocket; // works even for unicast
333 RTPSource* fRTPSource; RTCPInstance* fRTCPInstance;
334 FramedSource* fReadSource;
335 Boolean fReceiveRawMP3ADUs, fReceiveRawJPEGFrames;
336
337 // Other fields:
338 char* fSessionId; // used by RTSP
339};
340
341#endif
342