LCOV - code coverage report
Current view: top level - filters - in_rtp_rtsp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 120 180 66.7 %
Date: 2021-04-29 23:48:07 Functions: 10 10 100.0 %

          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*/

Generated by: LCOV version 1.13