UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
BasicRTSPOnlySubsession.cpp
Go to the documentation of this file.
1/*
2 * FILE: rtsp/BasicRTSPOnlySubsession.cpp
3 * AUTHORS: David Cassany <david.cassany@i2cat.net>
4 * Gerard Castillo <gerard.castillo@i2cat.net>
5 *
6 * Copyright (c) 2005-2010 Fundació i2CAT, Internet I Innovació Digital a Catalunya
7 * Copyright (c) 2014-2023 CESNET, z. s. p. o.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 *
23 * This product includes software developed by the Fundació i2CAT,
24 * Internet I Innovació Digital a Catalunya. This product also includes
25 * software developed by CESNET z.s.p.o.
26 *
27 * 4. Neither the name of the University nor of the Institute may be used
28 * to endorse or promote products derived from this software without
29 * specific prior written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
33 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
34 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
35 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
36 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
38 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
41 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
42 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 *
44 */
45
47#include <cassert>
48#include <BasicUsageEnvironment.hh>
49#include <RTSPServer.hh>
50#include <GroupsockHelper.hh>
51
52#include "audio/codec.h" // get_name_to_audio_codec
53#include "debug.h" // for MSG
54#include "messaging.h"
55#include "module.h" // for module_class, append_message...
56#include "utils/macros.h"
57#include "utils/net.h"
58#include "utils/sdp.h"
59#include "video_codec.h" // for get_codec_name
60
61#define MOD_NAME "[RTSP] "
62
65 Boolean reuseFirstSource, rtsp_types_t avType, int rtpPort,
67 return new BasicRTSPOnlySubsession(env, reuseFirstSource, avType,
69}
70
72 Boolean reuseFirstSource, rtsp_types_t avType, int rtpPort,
74 ServerMediaSubsession(env), fReuseFirstSource(reuseFirstSource),
75 fLastStreamToken(nullptr), rtsp_params(params)
76{
78 Vdestination = NULL;
79 Adestination = NULL;
80 gethostname(fCNAME, sizeof fCNAME);
81 this->avType = avType;
82 this->rtpPort = rtpPort;
83 fCNAME[sizeof fCNAME - 1] = '\0';
84
85 // print (preliminary) SDP
86 setSDPLines(AF_UNSPEC);
87 delete[] fSDPLines;
88 fSDPLines = nullptr;
89}
90
96
97const static struct media_spec {
98 unsigned estBitrate;
99 const char *mname;
100} media_params[] = {
101 { 0, nullptr }, // none
102 { 384, "audio" },
103 { 5000, "video" },
105static_assert(rtsp_type_audio == 1); // ensure the above mapping is correct
106static_assert(rtsp_type_video == 2);
107
108char const* BasicRTSPOnlySubsession::sdpLines(int addressFamily) {
109 if (fSDPLines == NULL) {
110 setSDPLines(addressFamily);
111 }
112 return fSDPLines;
113}
114
116 //TODO: should be more dynamic
117 const char *ip_ver_list_addr = nullptr;
118 const char *control = trackId();
119 switch (addressFamily) {
120 case AF_INET:
121 ip_ver_list_addr = "4 0.0.0.0";
122 break;
123 case AF_INET6:
124 ip_ver_list_addr = "6 ::";
125 break;
126 case AF_UNSPEC:
127 ip_ver_list_addr = "<VER> <TO_BE_FILLED>";
128 control = "<CONTROL>"; // is null here
129 break;
130 default:
131 abort();
132 }
133
134 const struct media_spec *mspec = &media_params[avType];
135 char rtpmapLine[STR_LEN];
136 int rtpPayloadType = avType == rtsp_type_audio
139 rtsp_params.adesc.ch_count, rtpmapLine)
141 if (rtpPayloadType < 0) {
142 MSG(ERROR, "Unsupported %s codec %s!\n", mspec[avType].mname,
146 }
147 //char const* auxSDPLine = "";
148
149 char const *const sdpFmt = "m=%s %u RTP/AVP %d\r\n"
150 "c=IN IP%s\r\n"
151 "b=AS:%u\r\n"
152 "a=rtcp:%d\r\n"
153 "%s"
154 "a=control:%s\r\n";
155 unsigned sdpFmtSize = strlen(sdpFmt) + strlen(mspec->mname) +
156 5 /* max short len */
157 + 3 /* max char len */
158 + strlen(ip_ver_list_addr) + 20 /* max int len */
159 + strlen(rtpmapLine) + strlen(control);
160 char *sdpLines = new char[sdpFmtSize];
161
162 snprintf(sdpLines, sdpFmtSize, sdpFmt, mspec->mname, // m= <media>
163 rtpPort, // fPortNumForSDP, // m= <port>
164 rtpPayloadType, // m= <fmt list>
165 ip_ver_list_addr, // c= address
166 mspec->estBitrate, // b=AS:<bandwidth>
167 rtpPort + 1,
168 rtpmapLine, // a=rtpmap:... (if present)
169 control); // a=control:<track-id>
170
172 MSG(VERBOSE, "SDP%s:\n%s\n",
173 addressFamily == AF_UNSPEC ? " (preliminary)" : "", fSDPLines);
174}
175
176void BasicRTSPOnlySubsession::getStreamParameters(unsigned /* clientSessionId */,
177 struct sockaddr_storage const &clientAddress, Port const& clientRTPPort,
178 Port const& clientRTCPPort, int /* tcpSocketNum */,
179 unsigned char /* rtpChannelId */, unsigned char /* rtcpChannelId */,
180 TLSState * /* tlsState */,
181 struct sockaddr_storage& /*destinationAddress*/, uint8_t& /*destinationTTL*/,
182 Boolean& /* isMulticast */, Port& serverRTPPort, Port& serverRTCPPort,
183 void*& /* streamToken */) {
184 if (avType == rtsp_type_video) {
186 serverRTPPort = rtp;
187 Port rtcp(rtsp_params.rtp_port_video + 1);
188 serverRTCPPort = rtcp;
189
190 delete Vdestination;
191 Vdestination = new Destinations(clientAddress, clientRTPPort,
192 clientRTCPPort);
193 }
194 if (avType == rtsp_type_audio) {
196 serverRTPPort = rtp;
197 Port rtcp(rtsp_params.rtp_port_audio + 1);
198 serverRTCPPort = rtcp;
199
200 delete Adestination;
201 Adestination = new Destinations(clientAddress, clientRTPPort,
202 clientRTCPPort);
203 }
204}
205
206void BasicRTSPOnlySubsession::startStream(unsigned /* clientSessionId */,
207 void* /* streamToken */, TaskFunc* /* rtcpRRHandler */,
208 void* /* rtcpRRHandlerClientData */, unsigned short& /* rtpSeqNum */,
209 unsigned& /* rtpTimestamp */,
210 ServerRequestAlternativeByteHandler* /* serverRequestAlternativeByteHandler */,
211 void* /* serverRequestAlternativeByteHandlerClientData */) {
212 struct response *resp = NULL;
213
214 if (Vdestination != NULL) {
215 if (avType == rtsp_type_video) {
216 char pathV[1024];
217
218 memset(pathV, 0, sizeof(pathV));
219 enum module_class path_sender[] = { MODULE_CLASS_SENDER,
221 append_message_path(pathV, sizeof(pathV), path_sender);
222
223 //CHANGE DST PORT
224 struct msg_sender *msgV1 = (struct msg_sender *) new_message(
225 sizeof(struct msg_sender));
226 msgV1->tx_port = ntohs(Vdestination->rtpPort.num());
228 resp = send_message(rtsp_params.parent, pathV, (struct message *) msgV1);
229 free_response(resp);
230
231 //CHANGE DST ADDRESS
232 struct msg_sender *msgV2 = (struct msg_sender *) new_message(
233 sizeof(struct msg_sender));
234 char host[IN6_MAX_ASCII_LEN + 1];
235 const int ret =
236 getnameinfo((struct sockaddr *) &Vdestination->addr,
237 sizeof Vdestination->addr, host,
238 sizeof host, nullptr, 0, NI_NUMERICHOST);
239 assert(ret == 0);
240 strncpy(msgV2->receiver, host,
241 sizeof(msgV2->receiver) - 1);
243
244 resp = send_message(rtsp_params.parent, pathV, (struct message *) msgV2);
245 free_response(resp);
246 }
247 }
248
249 if (Adestination != NULL) {
250 if (avType == rtsp_type_audio) {
251 char pathA[1024];
252
253 memset(pathA, 0, sizeof(pathA));
254 enum module_class path_sender[] = { MODULE_CLASS_AUDIO,
256 append_message_path(pathA, sizeof(pathA), path_sender);
257
258 //CHANGE DST PORT
259 struct msg_sender *msgA1 = (struct msg_sender *) new_message(
260 sizeof(struct msg_sender));
261 msgA1->tx_port = ntohs(Adestination->rtpPort.num());
263 resp = send_message(rtsp_params.parent, pathA, (struct message *) msgA1);
264 free_response(resp);
265 resp = NULL;
266
267 //CHANGE DST ADDRESS
268 struct msg_sender *msgA2 = (struct msg_sender *) new_message(
269 sizeof(struct msg_sender));
270 char host[IN6_MAX_ASCII_LEN + 1];
271 const int ret =
272 getnameinfo((struct sockaddr *) &Adestination->addr,
273 sizeof Adestination->addr, host,
274 sizeof host, nullptr, 0, NI_NUMERICHOST);
275 assert(ret == 0);
276 strncpy(msgA2->receiver, host,
277 sizeof(msgA2->receiver) - 1);
279
280 resp = send_message(rtsp_params.parent, pathA, (struct message *) msgA2);
281 free_response(resp);
282 resp = NULL;
283 }
284 }
285}
286
287void BasicRTSPOnlySubsession::deleteStream(unsigned /* clientSessionId */,
288 void*& /* streamToken */) {
289 if (Vdestination != NULL) {
290 if (avType == rtsp_type_video) {
291 char pathV[1024];
292 delete Vdestination;
293 Vdestination = NULL;
294 memset(pathV, 0, sizeof(pathV));
295 enum module_class path_sender[] = { MODULE_CLASS_SENDER,
297 append_message_path(pathV, sizeof(pathV), path_sender);
298
299 //CHANGE DST PORT
300 struct msg_sender *msgV1 = (struct msg_sender *) new_message(
301 sizeof(struct msg_sender));
304 struct response *resp;
305 resp = send_message(rtsp_params.parent, pathV, (struct message *) msgV1);
306 free_response(resp);
307
308 //CHANGE DST ADDRESS
309 struct msg_sender *msgV2 = (struct msg_sender *) new_message(
310 sizeof(struct msg_sender));
311 strncpy(msgV2->receiver, "127.0.0.1", sizeof(msgV2->receiver) - 1);
313 resp = send_message(rtsp_params.parent, pathV, (struct message *) msgV2);
314 free_response(resp);
315 }
316 }
317
318 if (Adestination != NULL) {
319 if (avType == rtsp_type_audio) {
320 char pathA[1024];
321 delete Adestination;
322 Adestination = NULL;
323 memset(pathA, 0, sizeof(pathA));
324 enum module_class path_sender[] = { MODULE_CLASS_AUDIO,
326 append_message_path(pathA, sizeof(pathA), path_sender);
327
328 //CHANGE DST PORT
329 struct msg_sender *msgA1 = (struct msg_sender *) new_message(
330 sizeof(struct msg_sender));
331
332 //TODO: GET AUDIO PORT SET (NOT A COMMON CASE WHEN RTSP IS ENABLED: DEFAULT -> vport + 2)
335 struct response *resp;
336 resp = send_message(rtsp_params.parent, pathA, (struct message *) msgA1);
337 free_response(resp);
338
339 //CHANGE DST ADDRESS
340 struct msg_sender *msgA2 = (struct msg_sender *) new_message(
341 sizeof(struct msg_sender));
342 strncpy(msgA2->receiver, "127.0.0.1", sizeof(msgA2->receiver) - 1);
344 resp = send_message(rtsp_params.parent, pathA, (struct message *) msgA2);
345 free_response(resp);
346 }
347 }
348}
349/* vi: set noexpandtab: */
static const struct media_spec media_params[]
const char * get_codec_name(codec_t codec)
void getStreamParameters(unsigned clientSessionId, struct sockaddr_storage const &clientAddress, Port const &clientRTPPort, Port const &clientRTCPPort, int tcpSocketNum, unsigned char rtpChannelId, unsigned char rtcpChannelId, TLSState *tlsState, struct sockaddr_storage &destinationAddress, uint8_t &destinationTTL, Boolean &isMulticast, Port &serverRTPPort, Port &serverRTCPPort, void *&streamToken) override
void setSDPLines(int addressFamily)
struct rtsp_server_parameters rtsp_params
static BasicRTSPOnlySubsession * createNew(UsageEnvironment &env, Boolean reuseFirstSource, rtsp_types_t avType, int rtpPort, struct rtsp_server_parameters)
char const * sdpLines(int addressFamily) override
void startStream(unsigned clientSessionId, void *streamToken, TaskFunc *rtcpRRHandler, void *rtcpRRHandlerClientData, unsigned short &rtpSeqNum, unsigned &rtpTimestamp, ServerRequestAlternativeByteHandler *serverRequestAlternativeByteHandler, void *serverRequestAlternativeByteHandlerClientData) override
BasicRTSPOnlySubsession(UsageEnvironment &env, Boolean reuseFirstSource, rtsp_types_t avType, int rtpPort, struct rtsp_server_parameters)
void deleteStream(unsigned clientSessionId, void *&streamToken) override
struct sockaddr_storage addr
const char * get_name_to_audio_codec(audio_codec_t codec)
Definition codec.cpp:450
static void new_message(struct module *m)
#define MSG(l, fmt,...)
Definition debug.h:96
module_class
Definition module.h:81
void append_message_path(char *buf, int buflen, const enum module_class *modules)
Definition module.c:187
@ MODULE_CLASS_NONE
Definition module.h:82
@ MODULE_CLASS_AUDIO
Definition module.h:90
@ MODULE_CLASS_SENDER
Definition module.h:87
@ STR_LEN
"standard" string length placeholder
Definition macros.h:134
struct response * send_message(struct module *root, const char *const_path, struct message *msg)
Sends message without waiting for response.
void free_response(struct response *r)
@ SENDER_MSG_CHANGE_RECEIVER
Definition messaging.h:84
@ SENDER_MSG_CHANGE_PORT
Definition messaging.h:85
#define IN6_MAX_ASCII_LEN
Definition net.h:50
rtsp_types_t
Definition rtsp_utils.h:4
@ rtsp_type_video
Definition rtsp_utils.h:7
@ rtsp_type_audio
Definition rtsp_utils.h:6
int get_audio_rtp_pt_rtpmap(audio_codec_t codec, int sample_rate, int channels, char rtpmapLine[STR_LEN])
Definition sdp.c:227
int get_video_rtp_pt_rtpmap(codec_t codec, char rtpmapLine[STR_LEN])
Definition sdp.c:304
int sample_rate
Definition types.h:78
int ch_count
Definition types.h:79
audio_codec_t codec
Definition types.h:80
char receiver[128]
Definition messaging.h:103
enum msg_sender_type type
Definition messaging.h:97
Definition rtp.c:274