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 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 | |
58 | class MediaSubsession; // forward |
59 | |
60 | class MediaSession: public Medium { |
61 | public: |
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 | |
94 | protected: // redefined virtual functions |
95 | virtual Boolean isMediaSession() const; |
96 | |
97 | protected: |
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 | |
120 | protected: |
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 | |
144 | class MediaSubsessionIterator { |
145 | public: |
146 | MediaSubsessionIterator(MediaSession const& session); |
147 | virtual ~MediaSubsessionIterator(); |
148 | |
149 | MediaSubsession* next(); // NULL if none |
150 | void reset(); |
151 | |
152 | private: |
153 | MediaSession const& fOurSession; |
154 | MediaSubsession* fNextPtr; |
155 | }; |
156 | |
157 | |
158 | class MediaSubsession { |
159 | public: |
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 | |
271 | protected: |
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 | |
296 | protected: |
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 | |