Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2017
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / RTP/RTSP input filter
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include "in_rtp.h"
27 :
28 : #ifndef GPAC_DISABLE_STREAMING
29 :
30 28 : static GF_Err rtpin_rtsp_process_response(GF_RTPInRTSP *sess, GF_RTSPCommand *com, GF_Err e)
31 : {
32 28 : if (!strcmp(com->method, GF_RTSP_DESCRIBE))
33 5 : return rtpin_rtsp_describe_process(sess, com, e);
34 23 : else if (!strcmp(com->method, GF_RTSP_SETUP))
35 6 : rtpin_rtsp_setup_process(sess, com, e);
36 17 : else if (!strcmp(com->method, GF_RTSP_TEARDOWN))
37 5 : rtpin_rtsp_teardown_process(sess, com, e);
38 12 : else if (!strcmp(com->method, GF_RTSP_PLAY) || !strcmp(com->method, GF_RTSP_PAUSE))
39 12 : rtpin_rtsp_usercom_process(sess, com, e);
40 : return GF_OK;
41 : }
42 :
43 811358 : void rtpin_rtsp_process_commands(GF_RTPInRTSP *sess)
44 : {
45 : GF_RTSPCommand *com;
46 : GF_Err e;
47 : u32 time;
48 : char sMsg[1000];
49 :
50 811358 : com = (GF_RTSPCommand *)gf_list_get(sess->rtsp_commands, 0);
51 :
52 : /*if asked or command to send, flushout TCP - TODO: check what's going on with ANNOUNCE*/
53 811358 : if ((com && !(sess->flags & RTSP_WAIT_REPLY) ) || (sess->flags & RTSP_TCP_FLUSH) ) {
54 : while (1) {
55 437 : e = gf_rtsp_session_read(sess->session);
56 437 : if (e) break;
57 : }
58 : }
59 :
60 : /*handle response or announce*/
61 811358 : if ( (com && (sess->flags & RTSP_WAIT_REPLY) ) /*|| (!com && sess->rtpin->handle_announce)*/) {
62 2007 : e = gf_rtsp_get_response(sess->session, sess->rtsp_rsp);
63 2007 : if (e!= GF_IP_NETWORK_EMPTY) {
64 28 : e = rtpin_rtsp_process_response(sess, com, e);
65 : /*this is a service connect error -> plugin may be discarded */
66 28 : if (e!=GF_OK) {
67 0 : gf_list_rem(sess->rtsp_commands, 0);
68 0 : gf_rtsp_command_del(com);
69 0 : gf_filter_setup_failure(sess->rtpin->filter, e);
70 0 : return;
71 : }
72 :
73 28 : gf_list_rem(sess->rtsp_commands, 0);
74 28 : gf_rtsp_command_del(com);
75 28 : sess->flags &= ~RTSP_WAIT_REPLY;
76 28 : sess->command_time = 0;
77 : } else {
78 1979 : u32 time_out = sess->rtpin->rtsp_timeout;
79 : /*evaluate timeout*/
80 1979 : time = gf_sys_clock() - sess->command_time;
81 :
82 1979 : if (!strcmp(com->method, GF_RTSP_DESCRIBE) && (time_out < 10000) ) time_out = 10000;
83 : /*don't waste time waiting for teardown ACK, half a sec is enough. If server is not replying
84 : in time it is likely to never reply (happens with RTP over RTSP) -> kill session
85 : and create new one*/
86 1414 : else if (!strcmp(com->method, GF_RTSP_TEARDOWN) && (time>=500) ) time = time_out;
87 :
88 : //signal what's going on
89 1979 : if (time >= time_out) {
90 0 : if (!strcmp(com->method, GF_RTSP_TEARDOWN)) {
91 0 : gf_rtsp_session_reset(sess->session, GF_TRUE);
92 : } else {
93 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[RTP] Request Timeout for command %s after %d ms\n", com->method, time));
94 : }
95 :
96 0 : rtpin_rtsp_process_response(sess, com, GF_IP_NETWORK_FAILURE);
97 0 : gf_list_rem(sess->rtsp_commands, 0);
98 0 : gf_rtsp_command_del(com);
99 0 : sess->flags &= ~RTSP_WAIT_REPLY;
100 0 : sess->command_time = 0;
101 0 : gf_rtsp_reset_aggregation(sess->session);
102 : }
103 : }
104 : return;
105 : }
106 :
107 809351 : if (!com) return;
108 :
109 : /*send command - check RTSP session state first*/
110 28 : switch (gf_rtsp_get_session_state(sess->session)) {
111 : case GF_RTSP_STATE_WAITING:
112 : case GF_RTSP_STATE_WAIT_FOR_CONTROL:
113 : return;
114 0 : case GF_RTSP_STATE_INVALIDATED:
115 0 : sprintf(sMsg, "Cannot send %s", com->method);
116 : rtpin_send_message(sess->rtpin, GF_IP_NETWORK_FAILURE, sMsg);
117 0 : gf_list_rem(sess->rtsp_commands, 0);
118 0 : gf_rtsp_command_del(com);
119 0 : sess->flags &= ~RTSP_WAIT_REPLY;
120 0 : sess->command_time = 0;
121 0 : return;
122 : }
123 : /*process*/
124 28 : if (!com->User_Agent) com->User_Agent = (char *) sess->rtpin->user_agent;
125 28 : com->Accept_Language = (char *) sess->rtpin->languages;
126 : /*if no session assigned and a session ID is valid, use it*/
127 28 : if (sess->session_id && !com->Session)
128 7 : com->Session = sess->session_id;
129 :
130 : /*preprocess describe before sending (always the ESD url thing)*/
131 28 : if (!strcmp(com->method, GF_RTSP_DESCRIBE)) {
132 5 : com->Session = NULL;
133 5 : if (!rtpin_rtsp_describe_preprocess(sess, com)) {
134 : e = GF_BAD_PARAM;
135 : goto exit;
136 : }
137 : }
138 : /*preprocess play/stop/pause before sending (aggregation)*/
139 28 : if (!strcmp(com->method, GF_RTSP_PLAY)
140 22 : || !strcmp(com->method, GF_RTSP_PAUSE)
141 16 : || !strcmp(com->method, GF_RTSP_TEARDOWN)) {
142 : //command is skipped
143 17 : if (!rtpin_rtsp_usercom_preprocess(sess, com)) {
144 : e = GF_BAD_PARAM;
145 : goto exit;
146 : }
147 : }
148 28 : e = gf_rtsp_send_command(sess->session, com);
149 28 : if (e) {
150 0 : sprintf(sMsg, "Cannot send %s", com->method);
151 : rtpin_send_message(sess->rtpin, e, sMsg);
152 0 : rtpin_rtsp_process_response(sess, com, e);
153 : } else {
154 28 : sess->command_time = gf_sys_clock();
155 28 : sess->flags |= RTSP_WAIT_REPLY;
156 : }
157 :
158 28 : exit:
159 : /*reset static strings*/
160 28 : com->User_Agent = NULL;
161 28 : com->Accept_Language = NULL;
162 28 : com->Session = NULL;
163 : /*remove command*/
164 28 : if (e) {
165 0 : gf_list_rem(sess->rtsp_commands, 0);
166 0 : gf_rtsp_command_del(com);
167 0 : sess->flags &= ~RTSP_WAIT_REPLY;
168 0 : sess->command_time = 0;
169 : }
170 : }
171 :
172 :
173 : /*locate channel - if requested remove from session*/
174 121 : GF_RTPInStream *rtpin_find_stream(GF_RTPIn *rtp, GF_FilterPid *opid, u32 ES_ID, char *es_control, Bool remove_stream)
175 : {
176 121 : u32 i=0;
177 : GF_RTPInStream *st;
178 :
179 245 : while ((st = (GF_RTPInStream *)gf_list_enum(rtp->streams, &i))) {
180 75 : if (opid && (st->opid==opid)) goto found;
181 3 : if (ES_ID && (st->ES_ID==ES_ID)) goto found;
182 3 : if (es_control && st->control) {
183 0 : char *ctrl_start = strstr(es_control, st->control);
184 0 : if (ctrl_start && !strcmp(ctrl_start, st->control)) goto found;
185 : }
186 : }
187 : return NULL;
188 :
189 72 : found:
190 72 : if (remove_stream) gf_list_rem(rtp->streams, i-1);
191 : return st;
192 : }
193 :
194 : /*locate session by control*/
195 26 : GF_RTPInRTSP *rtpin_rtsp_check(GF_RTPIn *rtp, char *control)
196 : {
197 26 : if (!control) return NULL;
198 :
199 6 : if (!strcmp(control, "*")) control = (char *) rtp->src;
200 6 : if (gf_rtsp_is_my_session(rtp->session->session, control)) return rtp->session;
201 : return NULL;
202 : }
203 :
204 5 : GF_RTPInRTSP *rtpin_rtsp_new(GF_RTPIn *rtp, char *session_control)
205 : {
206 : char *szCtrl, *szExt;
207 : GF_RTPInRTSP *tmp;
208 : GF_RTSPSession *rtsp;
209 :
210 5 : if (!session_control) return NULL;
211 :
212 5 : if (rtp->session) {
213 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP] Request more than one RTSP session for more URL, old code to patch !!\n"));
214 0 : return rtp->session;
215 : }
216 :
217 : /*little fix: some servers don't understand DESCRIBE URL/trackID=, so remove the trackID...*/
218 5 : szCtrl = gf_strdup(session_control);
219 5 : szExt = szCtrl ? gf_file_ext_start(szCtrl) : NULL;
220 5 : if (szExt) {
221 3 : szExt = strchr(szExt, '/');
222 3 : if (szExt) {
223 0 : if (!strnicmp(szExt+1, "trackID=", 8) || !strnicmp(szExt+1, "ESID=", 5) || !strnicmp(szExt+1, "ES_ID=", 6)) szExt[0] = 0;
224 : }
225 : }
226 :
227 5 : rtsp = gf_rtsp_session_new(szCtrl, rtp->default_port);
228 5 : gf_free(szCtrl);
229 :
230 5 : if (!rtsp) return NULL;
231 :
232 5 : GF_SAFEALLOC(tmp, GF_RTPInRTSP);
233 5 : if (!tmp) return NULL;
234 5 : tmp->rtpin = rtp;
235 5 : tmp->session = rtsp;
236 :
237 5 : if (rtp->interleave) {
238 1 : gf_rtsp_set_buffer_size(rtsp, rtp->block_size);
239 : } else {
240 4 : gf_rtsp_set_buffer_size(rtsp, RTSP_BUFFER_SIZE);
241 : }
242 5 : tmp->rtsp_commands = gf_list_new();
243 5 : tmp->rtsp_rsp = gf_rtsp_response_new();
244 :
245 5 : rtp->session = tmp;
246 5 : return tmp;
247 : }
248 :
249 20 : GF_Err rtpin_add_stream(GF_RTPIn *rtp, GF_RTPInStream *stream, char *session_control)
250 : {
251 : Bool has_aggregated_control;
252 : char *service_name;
253 20 : GF_RTPInRTSP *in_session = rtpin_rtsp_check(rtp, session_control);
254 :
255 : has_aggregated_control = GF_FALSE;
256 20 : if (session_control) {
257 : //if (!strcmp(session_control, "*")) session_control = NULL;
258 : has_aggregated_control = GF_TRUE;
259 : }
260 :
261 : /*regular setup in an established session (RTSP DESCRIBE)*/
262 20 : if (in_session) {
263 0 : in_session->flags |= RTSP_AGG_CONTROL;
264 0 : stream->rtsp = in_session;
265 0 : gf_list_add(rtp->streams, stream);
266 0 : return GF_OK;
267 : }
268 :
269 : /*setup through SDP with control - assume this is RTSP and try to create a session*/
270 20 : if (stream->control) {
271 : /*stream control is relative to main session*/
272 6 : if (strnicmp(stream->control, "rtsp://", 7) && strnicmp(stream->control, "rtspu://", 8) && strnicmp(stream->control, "satip://", 8)) {
273 : /*locate session by control - if no control was provided for the session, use default
274 : session*/
275 6 : if (!in_session) in_session = rtpin_rtsp_check(rtp, session_control ? session_control : "*");
276 : /*none found, try to create one*/
277 6 : if (!in_session) in_session = rtpin_rtsp_new(rtp, session_control);
278 : /*cannot add an RTSP session for this channel, check if multicast*/
279 : // if (!in_session && gf_rtp_is_unicast(stream->rtp_ch) ) return GF_SERVICE_ERROR;
280 : }
281 : /*stream control is absolute*/
282 : else {
283 : char *ctrl;
284 0 : in_session = rtpin_rtsp_check(rtp, stream->control);
285 0 : if (!in_session) in_session = rtpin_rtsp_check(rtp, session_control);
286 0 : if (!in_session) {
287 0 : if (session_control && strstr(stream->control, session_control))
288 0 : in_session = rtpin_rtsp_new(rtp, session_control);
289 : else
290 0 : in_session = rtpin_rtsp_new(rtp, stream->control);
291 0 : if (!in_session) return GF_SERVICE_ERROR;
292 : }
293 : /*remove session control part from channel control*/
294 0 : service_name = in_session->session->Service;
295 0 : ctrl = strstr(stream->control, service_name);
296 0 : if (ctrl && (strlen(ctrl) != strlen(service_name)) ) {
297 0 : ctrl += strlen(service_name) + 1;
298 0 : service_name = gf_strdup(ctrl);
299 0 : gf_free(stream->control);
300 0 : stream->control = service_name;
301 : }
302 : }
303 : }
304 : /*no control specified, assume this is multicast*/
305 : else {
306 : in_session = NULL;
307 : }
308 :
309 6 : if (in_session) {
310 6 : if (has_aggregated_control)
311 0 : in_session->flags |= RTSP_AGG_CONTROL;
312 14 : } else if (stream->control) {
313 0 : gf_free(stream->control);
314 0 : stream->control = NULL;
315 : }
316 20 : stream->rtsp = in_session;
317 20 : gf_list_add(rtp->streams, stream);
318 20 : return GF_OK;
319 : }
320 :
321 :
322 6 : void rtpin_remove_stream(GF_RTPIn *rtp, GF_RTPInStream *stream)
323 : {
324 6 : u32 i=0;
325 : GF_RTPInStream *st;
326 13 : while ((st = (GF_RTPInStream *)gf_list_enum(rtp->streams, &i))) {
327 1 : if (st == stream) {
328 0 : gf_list_rem(rtp->streams, i-1);
329 0 : break;
330 : }
331 : }
332 6 : }
333 :
334 5 : static void rtpin_rtsp_reset(GF_RTPInRTSP *sess, GF_Err e)
335 : {
336 5 : if (!sess) return;
337 :
338 : //destroy command list
339 5 : while (gf_list_count(sess->rtsp_commands)) {
340 0 : GF_RTSPCommand *com = (GF_RTSPCommand *)gf_list_get(sess->rtsp_commands, 0);
341 0 : gf_list_rem(sess->rtsp_commands, 0);
342 :
343 : /*reset static strings*/
344 0 : com->User_Agent = NULL;
345 0 : com->Accept_Language = NULL;
346 0 : com->Session = NULL;
347 :
348 0 : gf_rtsp_command_del(com);
349 : //first = 0;
350 : }
351 : /*reset session state*/
352 5 : gf_rtsp_session_reset(sess->session, GF_TRUE);
353 5 : sess->flags &= ~RTSP_WAIT_REPLY;
354 : }
355 :
356 :
357 20 : void rtpin_rtsp_del(GF_RTPInRTSP *sess)
358 : {
359 20 : if (!sess) return;
360 5 : rtpin_rtsp_reset(sess, GF_OK);
361 5 : gf_list_del(sess->rtsp_commands);
362 5 : gf_rtsp_response_del(sess->rtsp_rsp);
363 5 : gf_rtsp_session_del(sess->session);
364 5 : if (sess->control) gf_free(sess->control);
365 5 : if (sess->session_id) gf_free(sess->session_id);
366 5 : if (sess->satip_server) gf_free(sess->satip_server);
367 5 : gf_free(sess);
368 : }
369 :
370 10 : void rtpin_send_message(GF_RTPIn *ctx, GF_Err e, const char *message)
371 : {
372 : /* GF_NetworkCommand com;
373 : memset(&com, 0, sizeof(com));
374 : com.command_type = GF_NET_SERVICE_EVENT;
375 : com.send_event.evt.type = GF_EVENT_MESSAGE;
376 : com.send_event.evt.message.message = message;
377 : com.send_event.evt.message.error = e;
378 : gf_service_command(service, &com, GF_OK);
379 : */
380 :
381 10 : }
382 :
383 : #endif /*GPAC_DISABLE_STREAMING*/
|