LCOV - code coverage report
Current view: top level - filters - in_rtp_signaling.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 211 393 53.7 %
Date: 2021-04-29 23:48:07 Functions: 13 14 92.9 %

          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             : #include <gpac/internal/ietf_dev.h>
      28             : 
      29             : #ifndef GPAC_DISABLE_STREAMING
      30             : 
      31             : static Bool rtpin_stream_is_valid(GF_RTPIn *rtp, GF_RTPInStream *stream)
      32             : {
      33          24 :         u32 i=0;
      34             :         GF_RTPInStream *st;
      35          28 :         while ((st = (GF_RTPInStream *)gf_list_enum(rtp->streams, &i))) {
      36          28 :                 if (st == stream) return GF_TRUE;
      37             :         }
      38             :         return GF_FALSE;
      39             : }
      40             : 
      41             : /*this prevent sending teardown on session with running channels*/
      42           6 : static Bool rtpin_rtsp_is_active(GF_RTPInStream *stream)
      43             : {
      44             :         GF_RTPInStream *a_st;
      45             :         u32 i, count;
      46           6 :         i = count = 0;
      47          14 :         while ((a_st = (GF_RTPInStream *)gf_list_enum(stream->rtpin->streams, &i))) {
      48           8 :                 if (a_st->rtsp != stream->rtsp) continue;
      49             :                 /*count only active channels*/
      50           8 :                 if (a_st->status == RTP_Running) count++;
      51             :         }
      52           6 :         return count ? GF_TRUE : GF_FALSE;
      53             : }
      54             : 
      55             : static void rtpin_rtsp_queue_command(GF_RTPInRTSP *sess, GF_RTPInStream *stream, GF_RTSPCommand *com, Bool needs_sess_id)
      56             : {
      57             :         if (needs_sess_id) {
      58          23 :                 com->Session = sess->session_id;
      59             :         }
      60          28 :         gf_list_add(sess->rtsp_commands, com);
      61             : }
      62             : 
      63             : 
      64             : 
      65             : /*
      66             :                                                 channel setup functions
      67             :                                                                                                                                 */
      68             : 
      69           6 : void rtpin_rtsp_setup_send(GF_RTPInStream *stream)
      70             : {
      71             :         GF_RTSPCommand *com;
      72             :         GF_RTSPTransport *trans;
      73             : 
      74           6 :         com = gf_rtsp_command_new();
      75           6 :         com->method = gf_strdup(GF_RTSP_SETUP);
      76             : 
      77             :         //setup ports if unicast non interleaved or multicast
      78           6 :         if (gf_rtp_is_unicast(stream->rtp_ch) && (stream->rtpin->interleave != 1) && !gf_rtp_is_interleaved(stream->rtp_ch) ) {
      79           5 :                 gf_rtp_set_ports(stream->rtp_ch, stream->rtpin->firstport);
      80           1 :         } else if (stream->rtpin->force_mcast) {
      81           0 :                 gf_rtp_set_ports(stream->rtp_ch, stream->rtpin->firstport);
      82             :         }
      83             : 
      84           6 :         trans = gf_rtsp_transport_clone((GF_RTSPTransport *)gf_rtp_get_transport(stream->rtp_ch));
      85             : 
      86             :         /*some servers get confused when trying to resetup on the same remote ports, so reset info*/
      87           6 :         trans->port_first = trans->port_last = 0;
      88           6 :         trans->SSRC = 0;
      89             : 
      90             :         /*override transport: */
      91             :         /*1: multicast forced*/
      92           6 :         if (stream->rtpin->force_mcast) {
      93           1 :                 trans->IsUnicast = GF_FALSE;
      94           1 :                 trans->destination = gf_strdup(stream->rtpin->force_mcast);
      95           1 :                 trans->TTL = stream->rtpin->ttl;
      96           1 :                 if (trans->Profile) gf_free(trans->Profile);
      97           1 :                 trans->Profile = gf_strdup(GF_RTSP_PROFILE_RTP_AVP);
      98           1 :                 if (!(stream->rtsp->flags & RTSP_DSS_SERVER) ) {
      99           1 :                         trans->port_first = trans->client_port_first;
     100           1 :                         trans->port_last = trans->client_port_last;
     101             :                         /*this is correct but doesn't work with DSS: the server expects "client_port" to indicate
     102             :                         the multicast port, not "port" - this will send both*/
     103             :                         //trans->client_port_first = trans->client_port_last = 0;
     104             :                 }
     105           1 :                 gf_rtp_setup_transport(stream->rtp_ch, trans, NULL);
     106             :         }
     107             :         /*2: RTP over RTSP forced*/
     108           5 :         else if (stream->rtsp->flags & RTSP_FORCE_INTER) {
     109           1 :                 if (trans->Profile) gf_free(trans->Profile);
     110           1 :                 trans->Profile = gf_strdup(GF_RTSP_PROFILE_RTP_AVP_TCP);
     111             :                 //some servers expect the interleaved to be set during the setup request
     112           1 :                 trans->IsInterleaved = GF_TRUE;
     113           1 :                 trans->rtpID = 2*gf_list_find(stream->rtpin->streams, stream);
     114           1 :                 trans->rtcpID = trans->rtpID+1;
     115           1 :                 gf_rtp_setup_transport(stream->rtp_ch, trans, NULL);
     116             :         }
     117             : 
     118           6 :         if (trans->source) {
     119           6 :                 gf_free(trans->source);
     120           6 :                 trans->source = NULL;
     121             :         }
     122             : 
     123             :         /*turn off interleaving in case of re-setup, some servers don't like it (we still signal it
     124             :         through RTP/AVP/TCP profile so it's OK)*/
     125             : //      trans->IsInterleaved = 0;
     126           6 :         gf_list_add(com->Transports, trans);
     127           6 :         if (strlen(stream->control)) com->ControlString = gf_strdup(stream->control);
     128             : 
     129           6 :         com->user_data = stream;
     130           6 :         stream->status = RTP_WaitingForAck;
     131             : 
     132           6 :         rtpin_rtsp_queue_command(stream->rtsp, stream, com, GF_TRUE);
     133           6 : }
     134             : 
     135             : /*filter setup if no session (rtp only)*/
     136           6 : GF_Err rtpin_stream_setup(GF_RTPInStream *stream, RTPIn_StreamDescribe *ch_desc)
     137             : {
     138             :         GF_Err resp;
     139             : 
     140             :         /*assign ES_ID of the channel*/
     141           6 :         if (ch_desc && !stream->ES_ID && ch_desc->ES_ID) stream->ES_ID = ch_desc->ES_ID;
     142             : 
     143           6 :         stream->status = RTP_Setup;
     144             : 
     145             :         /*assign channel handle if not done*/
     146           6 :         if (ch_desc && stream->opid) {
     147             :                 assert(stream->opid == ch_desc->opid);
     148           0 :         } else if (!stream->opid && stream->rtsp && !stream->rtsp->satip) {
     149             :                 assert(ch_desc);
     150             :                 assert(ch_desc->opid);
     151           0 :                 stream->opid = ch_desc->opid;
     152             :         }
     153             : 
     154             :         /*no session , setup for pure rtp*/
     155           6 :         if (!stream->rtsp) {
     156           0 :                 stream->flags |= RTP_CONNECTED;
     157             :                 /*init rtp*/
     158           0 :                 resp = rtpin_stream_init(stream, GF_FALSE);
     159             :                 /*send confirmation to user*/
     160           0 :                 rtpin_stream_ack_connect(stream, resp);
     161             :         } else {
     162           6 :                 rtpin_rtsp_setup_send(stream);
     163             :         }
     164           6 :         return GF_OK;
     165             : }
     166             : 
     167           0 : static GF_Err rtpin_rtsp_tcp_send_report(void *par, void *par2, Bool is_rtcp, u8 *pck, u32 pck_size)
     168             : {
     169           0 :         return GF_OK;
     170             : }
     171             : 
     172           6 : void rtpin_rtsp_setup_process(GF_RTPInRTSP *sess, GF_RTSPCommand *com, GF_Err e)
     173             : {
     174             :         GF_RTPInStream *stream;
     175             :         u32 i;
     176             :         GF_RTSPTransport *trans;
     177             : 
     178           6 :         stream = (GF_RTPInStream *)com->user_data;
     179           6 :         if (e) goto exit;
     180             : 
     181           6 :         switch (sess->rtsp_rsp->ResponseCode) {
     182             :         case NC_RTSP_OK:
     183             :                 break;
     184             :         case NC_RTSP_Not_Found:
     185             :                 e = GF_STREAM_NOT_FOUND;
     186             :                 goto exit;
     187           0 :         default:
     188             :                 e = GF_SERVICE_ERROR;
     189           0 :                 goto exit;
     190             :         }
     191             :         e = GF_SERVICE_ERROR;
     192           6 :         if (!stream) goto exit;
     193             : 
     194             :         /*assign session ID*/
     195           6 :         if (!sess->rtsp_rsp->Session) {
     196             :                 e = GF_SERVICE_ERROR;
     197             :                 goto exit;
     198             :         }
     199           6 :         if (!sess->session_id) sess->session_id = gf_strdup(sess->rtsp_rsp->Session);
     200             :         assert(!stream->session_id);
     201             : 
     202             :         /*transport setup: break at the first correct transport */
     203           6 :         i=0;
     204          12 :         while ((trans = (GF_RTSPTransport *)gf_list_enum(sess->rtsp_rsp->Transports, &i))) {
     205             :                 /*copy over previous ports (hack for some servers overriding client ports)*/
     206           6 :                 if (stream->rtpin->use_client_ports)
     207           0 :                         gf_rtp_get_ports(stream->rtp_ch, &trans->client_port_first, &trans->client_port_last);
     208             : 
     209           6 :                 if (gf_rtp_is_interleaved(stream->rtp_ch) && !trans->IsInterleaved) {
     210           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTSP] Requested interleaved RTP over RTSP but server did not setup interleave - cannot process command\n"));
     211             :                         e = GF_REMOTE_SERVICE_ERROR;
     212           0 :                         continue;
     213             :                 }
     214             : 
     215           6 :                 e = gf_rtp_setup_transport(stream->rtp_ch, trans, gf_rtsp_get_server_name(sess->session));
     216           6 :                 if (!e) break;
     217             :         }
     218           6 :         if (e) goto exit;
     219             : 
     220           6 :         e = rtpin_stream_init(stream, GF_FALSE);
     221           6 :         if (e) goto exit;
     222           6 :         stream->status = RTP_Connected;
     223             : 
     224             :         //in case this is TCP channel, setup callbacks
     225           6 :         stream->flags &= ~RTP_INTERLEAVED;
     226           6 :         if (gf_rtp_is_interleaved(stream->rtp_ch)) {
     227           1 :                 stream->flags |= RTP_INTERLEAVED;
     228           1 :                 gf_rtsp_set_interleave_callback(sess->session, rtpin_rtsp_data_cbk);
     229             : 
     230           1 :                 gf_rtp_set_interleave_callbacks(stream->rtp_ch, rtpin_rtsp_tcp_send_report, stream, stream);
     231           1 :                 sess->flags |= RTSP_TCP_FLUSH;
     232             : #ifdef GPAC_ENABLE_COVERAGE
     233           1 :                 if (gf_sys_is_cov_mode())
     234             :                         rtpin_rtsp_tcp_send_report(NULL, NULL, GF_FALSE, NULL, 0);
     235             : #endif
     236             :         }
     237             : 
     238           6 :         if (sess->satip) {
     239             :                 RTPIn_StreamControl *ch_ctrl = NULL;
     240           0 :                 GF_RTSPCommand *a_com = gf_rtsp_command_new();
     241           0 :                 a_com->method = gf_strdup(GF_RTSP_PLAY);
     242           0 :                 GF_SAFEALLOC(ch_ctrl, RTPIn_StreamControl);
     243           0 :                 if (ch_ctrl) {
     244           0 :                         ch_ctrl->stream = stream;
     245           0 :                         a_com->user_data = ch_ctrl;
     246             :                 }
     247           0 :                 rtpin_rtsp_queue_command(sess, stream, a_com, GF_TRUE);
     248             :         }
     249             : 
     250          12 : exit:
     251             :         /*confirm only on first connect, otherwise this is a re-SETUP of the rtsp session, not the channel*/
     252           6 :         if (stream && ! (stream->flags & RTP_CONNECTED) ) {
     253           6 :                 if (!e)
     254           6 :                         stream->flags |= RTP_CONNECTED;
     255           6 :                 rtpin_stream_ack_connect(stream, e);
     256             :         }
     257           6 :         com->user_data = NULL;
     258           6 : }
     259             : 
     260             : 
     261             : /*
     262             :                                                 session/channel describe functions
     263             :                                                                                                                                 */
     264             : /*filter describe commands in case of ESD URLs*/
     265           5 : Bool rtpin_rtsp_describe_preprocess(GF_RTPInRTSP *sess, GF_RTSPCommand *com)
     266             : {
     267             :         GF_RTPInStream *stream;
     268             :         RTPIn_StreamDescribe *ch_desc;
     269             :         /*not a channel describe*/
     270           5 :         if (!com->user_data) {
     271           5 :                 rtpin_send_message(sess->rtpin, GF_OK, "Connecting...");
     272           5 :                 return GF_TRUE;
     273             :         }
     274             : 
     275             :         ch_desc = (RTPIn_StreamDescribe *)com->user_data;
     276           0 :         stream = rtpin_find_stream(sess->rtpin, NULL, ch_desc->ES_ID, ch_desc->esd_url, GF_FALSE);
     277           0 :         if (!stream) return GF_TRUE;
     278             : 
     279             :         /*channel has been described already, skip describe and send setup directly*/
     280           0 :         rtpin_stream_setup(stream, ch_desc);
     281             : 
     282           0 :         if (ch_desc->esd_url) gf_free(ch_desc->esd_url);
     283           0 :         gf_free(ch_desc);
     284           0 :         return GF_FALSE;
     285             : }
     286             : 
     287             : /*process describe reply*/
     288           5 : GF_Err rtpin_rtsp_describe_process(GF_RTPInRTSP *sess, GF_RTSPCommand *com, GF_Err e)
     289             : {
     290             :         GF_RTPInStream *stream;
     291             :         RTPIn_StreamDescribe *ch_desc;
     292             : 
     293             :         stream = NULL;
     294           5 :         ch_desc = (RTPIn_StreamDescribe *)com->user_data;
     295           5 :         if (e) goto exit;
     296             : 
     297           5 :         switch (sess->rtsp_rsp->ResponseCode) {
     298             :         //TODO handle all 3xx codes  (redirections)
     299           0 :         case NC_RTSP_Multiple_Choice:
     300           0 :                 e = ch_desc ? GF_STREAM_NOT_FOUND : GF_URL_ERROR;
     301             :                 goto exit;
     302             :         case NC_RTSP_Not_Found:
     303             :                 e = GF_URL_ERROR;
     304             :                 goto exit;
     305             :         case NC_RTSP_OK:
     306             :                 break;
     307           0 :         default:
     308             :                 //we should have a basic error code mapping here
     309             :                 e = GF_SERVICE_ERROR;
     310           0 :                 goto exit;
     311             :         }
     312             : 
     313             :         stream = NULL;
     314           5 :         if (ch_desc) {
     315           0 :                 stream = rtpin_find_stream(sess->rtpin, ch_desc->opid, ch_desc->ES_ID, ch_desc->esd_url, GF_FALSE);
     316             :         } else {
     317           5 :                 rtpin_send_message(sess->rtpin, GF_OK, "Connected");
     318             :         }
     319             : 
     320             :         /*error on loading SDP is done internally*/
     321           5 :         rtpin_load_sdp(sess->rtpin, sess->rtsp_rsp->body, sess->rtsp_rsp->Content_Length, stream);
     322             : 
     323           5 :         if (!ch_desc) goto exit;
     324           0 :         if (!stream) {
     325             :                 e = GF_STREAM_NOT_FOUND;
     326             :                 goto exit;
     327             :         }
     328           0 :         e = rtpin_stream_setup(stream, ch_desc);
     329             : 
     330          10 : exit:
     331           5 :         com->user_data = NULL;
     332           5 :         if (e) {
     333           0 :                 if (!ch_desc) {
     334           0 :                         sess->connect_error = e;
     335           0 :                         return e;
     336           0 :                 } else if (stream) {
     337           0 :                         rtpin_stream_ack_connect(stream, e);
     338             :                 } else {
     339             :                         //TODO - check if this is correct
     340           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[RTPIn] code not tested file %s line %d !!\n", __FILE__, __LINE__));
     341           0 :                         gf_filter_setup_failure(sess->rtpin->filter, e);
     342             :                 }
     343             :         }
     344           5 :         if (ch_desc) gf_free(ch_desc);
     345             :         return GF_OK;
     346             : }
     347             : 
     348             : /*send describe*/
     349           5 : void rtpin_rtsp_describe_send(GF_RTPInRTSP *sess, char *esd_url, GF_FilterPid *opid)
     350             : {
     351             :         RTPIn_StreamDescribe *ch_desc;
     352             :         GF_RTSPCommand *com;
     353             : 
     354             :         /*locate the channel by URL - if we have one, this means the channel is already described
     355             :         this happens when 2 ESD with URL use the same RTSP service - skip describe and send setup*/
     356           5 :         if (esd_url || opid) {
     357           0 :                 GF_RTPInStream *stream = rtpin_find_stream(sess->rtpin, opid, 0, esd_url, GF_FALSE);
     358           0 :                 if (stream) {
     359           0 :                         if (!stream->opid) stream->opid = opid;
     360           0 :                         switch (stream->status) {
     361           0 :                         case RTP_Connected:
     362             :                         case RTP_Running:
     363           0 :                                 rtpin_stream_ack_connect(stream, GF_OK);
     364           0 :                                 return;
     365             :                         default:
     366             :                                 break;
     367             :                         }
     368           0 :                         ch_desc = (RTPIn_StreamDescribe *)gf_malloc(sizeof(RTPIn_StreamDescribe));
     369           0 :                         ch_desc->esd_url = esd_url ? gf_strdup(esd_url) : NULL;
     370           0 :                         ch_desc->opid = opid;
     371           0 :                         rtpin_stream_setup(stream, ch_desc);
     372             : 
     373           0 :                         if (esd_url) gf_free(ch_desc->esd_url);
     374           0 :                         gf_free(ch_desc);
     375           0 :                         return;
     376             :                 }
     377             :                 /*channel not found, send describe on service*/
     378             :         }
     379             : 
     380             :         /*send describe*/
     381           5 :         com = gf_rtsp_command_new();
     382           5 :         if (!sess->satip) {
     383           5 :                 com->method = gf_strdup(GF_RTSP_DESCRIBE);
     384             :         } else {
     385             :                 GF_Err e;
     386             :                 GF_RTSPTransport *trans;
     387             :                 GF_RTPInStream *stream = NULL;
     388             : 
     389           0 :                 com->method = gf_strdup(GF_RTSP_SETUP);
     390             : 
     391             :                 /*setup transport ports*/
     392           0 :                 GF_SAFEALLOC(trans, GF_RTSPTransport);
     393           0 :                 if (trans) {
     394           0 :                         trans->IsUnicast = GF_TRUE;
     395           0 :                         trans->client_port_first = sess->rtpin->satip_port;
     396           0 :                         trans->client_port_last = sess->rtpin->satip_port+1;
     397           0 :                         trans->Profile = gf_strdup(GF_RTSP_PROFILE_RTP_AVP);
     398           0 :                         gf_list_add(com->Transports, trans);
     399             :                 }
     400             :                 
     401             :                 /*hardcoded channel*/
     402           0 :                 stream = rtpin_stream_new_satip(sess->rtpin, sess->satip_server);
     403           0 :                 if (!stream) {
     404           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("SAT>IP: couldn't create the RTP stream.\n"));
     405             :                         return;
     406             :                 }
     407           0 :                 e = rtpin_add_stream(sess->rtpin, stream, "*");
     408           0 :                 if (e) {
     409           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("SAT>IP: couldn't add the RTP stream.\n"));
     410             :                         return;
     411             :                 }
     412           0 :                 com->user_data = stream;
     413             :         }
     414             : 
     415           5 :         if (opid || esd_url) {
     416           0 :                 com->Accept = gf_strdup("application/sdp");
     417           0 :                 com->ControlString = esd_url ? gf_strdup(esd_url) : NULL;
     418             : 
     419           0 :                 ch_desc = (RTPIn_StreamDescribe *)gf_malloc(sizeof(RTPIn_StreamDescribe));
     420           0 :                 ch_desc->esd_url = esd_url ? gf_strdup(esd_url) : NULL;
     421           0 :                 ch_desc->opid = opid;
     422             : 
     423           0 :                 com->user_data = ch_desc;
     424             :         } else {
     425             :                 //always accept both SDP and IOD
     426           5 :                 com->Accept = gf_strdup("application/sdp, application/mpeg4-iod");
     427             : //              com->Accept = gf_strdup("application/sdp");
     428             :         }
     429             : 
     430             :         /*need better tuning ...*/
     431           5 :         if (sess->rtpin->bandwidth)
     432           0 :                 com->Bandwidth = sess->rtpin->bandwidth;
     433             : 
     434             :         rtpin_rtsp_queue_command(sess, NULL, com, GF_FALSE);
     435             : }
     436             : 
     437             : 
     438          12 : static void rtpin_rtsp_skip_command(GF_RTPInStream *stream)
     439             : {
     440             :         u32 i;
     441             :         GF_RTPInStream *a_st;
     442          24 :         if (!stream || (stream->flags & RTP_SKIP_NEXT_COM) || !(stream->rtsp->flags & RTSP_AGG_CONTROL) ) return;
     443           0 :         i=0;
     444           0 :         while ((a_st = (GF_RTPInStream *)gf_list_enum(stream->rtpin->streams, &i))) {
     445           0 :                 if ((stream == a_st) || (a_st->rtsp != stream->rtsp) ) continue;
     446           0 :                 if (a_st->status>=RTP_Connected)
     447           0 :                         a_st->flags |= RTP_SKIP_NEXT_COM;
     448             :         }
     449             : }
     450             : 
     451             : 
     452             : /*
     453             :                                                 channel control functions
     454             :                                                                                                                                 */
     455             : /*remove command if session is using aggregated control*/
     456          17 : Bool rtpin_rtsp_usercom_preprocess(GF_RTPInRTSP *sess, GF_RTSPCommand *com)
     457             : {
     458             :         RTPIn_StreamControl *ch_ctrl;
     459             :         GF_RTPInStream *stream;
     460             :         GF_Err e;
     461             :         Bool skip_it;
     462             : 
     463             :         ch_ctrl = NULL;
     464          17 :         if (strcmp(com->method, GF_RTSP_TEARDOWN)) ch_ctrl = (RTPIn_StreamControl *)com->user_data;
     465          12 :         if (!ch_ctrl || !ch_ctrl->stream) return GF_TRUE;
     466             :         stream = ch_ctrl->stream;
     467             : 
     468          12 :         if (!sess->satip) {
     469          24 :                 if (!stream->opid || !rtpin_stream_is_valid(sess->rtpin, stream)) {
     470           0 :                         gf_free(ch_ctrl);
     471           0 :                         com->user_data = NULL;
     472           0 :                         return GF_FALSE;
     473             :                 }
     474             : 
     475             :                 assert(stream->rtsp == sess);
     476             :                 assert(stream->opid == ch_ctrl->evt.base.on_pid);
     477             :         }
     478             : 
     479             :         skip_it = GF_FALSE;
     480          12 :         if (!com->Session) {
     481             :                 /*re-SETUP failed*/
     482           0 :                 if (!strcmp(com->method, GF_RTSP_PLAY) || !strcmp(com->method, GF_RTSP_PAUSE)) {
     483             :                         e = GF_SERVICE_ERROR;
     484             :                         goto err_exit;
     485             :                 }
     486             :                 /*this is a stop, no need for SessionID just skip*/
     487             :                 skip_it = GF_TRUE;
     488             :         } else {
     489          12 :                 rtpin_rtsp_skip_command(stream);
     490             :         }
     491             : 
     492             :         /*check if aggregation discards this command*/
     493          12 :         if (skip_it || ( (sess->flags & RTSP_AGG_CONTROL) && (stream->flags & RTP_SKIP_NEXT_COM) )) {
     494           0 :                 stream->flags &= ~RTP_SKIP_NEXT_COM;
     495           0 :                 gf_free(ch_ctrl);
     496           0 :                 com->user_data = NULL;
     497           0 :                 return GF_FALSE;
     498             :         }
     499             :         return GF_TRUE;
     500             : 
     501             : err_exit:
     502           0 :         gf_rtsp_reset_aggregation(stream->rtsp->session);
     503           0 :         stream->status = RTP_Disconnected;
     504           0 :         stream->check_rtp_time = RTP_SET_TIME_NONE;
     505             : 
     506           0 :         GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTSP] Error processing event %s: %s\n", gf_filter_event_name(ch_ctrl->evt.base.type), gf_error_to_string(e) ));
     507             : 
     508           0 :         gf_free(ch_ctrl);
     509           0 :         com->user_data = NULL;
     510           0 :         return GF_FALSE;
     511             : }
     512             : 
     513          12 : void rtpin_rtsp_usercom_process(GF_RTPInRTSP *sess, GF_RTSPCommand *com, GF_Err e)
     514             : {
     515             :         RTPIn_StreamControl *ch_ctrl;
     516             :         GF_RTPInStream *stream, *agg_st;
     517             :         u32 i, count;
     518             :         GF_RTPInfo *info;
     519             : 
     520          12 :         ch_ctrl = (RTPIn_StreamControl *)com->user_data;
     521          12 :         stream = ch_ctrl->stream;
     522             : 
     523          12 :         if (stream) {
     524          24 :                 if (!stream->opid || !rtpin_stream_is_valid(sess->rtpin, stream)) {
     525           0 :                         gf_free(ch_ctrl);
     526           0 :                         com->user_data = NULL;
     527           0 :                         return;
     528             :                 }
     529             : 
     530             :                 assert(stream->opid==ch_ctrl->evt.base.on_pid);
     531             :         }
     532             : 
     533             :         /*some consistency checking: on interleaved sessions, some servers do NOT reply to the
     534             :         teardown. If our command is STOP just skip the error notif*/
     535          12 :         if (e) {
     536           0 :                 if (!strcmp(com->method, GF_RTSP_TEARDOWN)) {
     537             :                         goto process_reply;
     538             :                 } else {
     539             :                         /*spec is not really clear about what happens if the server doesn't support
     540             :                         non aggregated operations. Since this happen only on pause/play, we consider
     541             :                         that no error occured and wait for next play*/
     542           0 :                         if (sess->rtsp_rsp->ResponseCode == NC_RTSP_Only_Aggregate_Operation_Allowed) {
     543           0 :                                 sess->flags |= RTSP_AGG_ONLY;
     544           0 :                                 sess->rtsp_rsp->ResponseCode = NC_RTSP_OK;
     545             :                         } else {
     546             :                                 goto err_exit;
     547             :                         }
     548             :                 }
     549             :         }
     550             : 
     551          12 :         switch (sess->rtsp_rsp->ResponseCode) {
     552             :         //handle all 3xx codes  (redirections)
     553             :         case NC_RTSP_Method_Not_Allowed:
     554             :                 e = GF_NOT_SUPPORTED;
     555             :                 goto err_exit;
     556             :         case NC_RTSP_OK:
     557             :                 break;
     558           0 :         default:
     559             :                 //we should have a basic error code mapping here
     560             :                 e = GF_SERVICE_ERROR;
     561           0 :                 goto err_exit;
     562             :         }
     563             : 
     564           0 : process_reply:
     565             : 
     566          24 :         if ( (ch_ctrl->evt.base.type==GF_FEVT_PLAY)
     567             :                 || (ch_ctrl->evt.base.type==GF_FEVT_SET_SPEED)
     568          12 :                 || (ch_ctrl->evt.base.type==GF_FEVT_RESUME) ) {
     569             : 
     570             :                 //auto-detect any aggregated control if not done yet
     571           6 :                 if (gf_list_count(sess->rtsp_rsp->RTP_Infos) > 1) {
     572           0 :                         sess->flags |= RTSP_AGG_CONTROL;
     573             :                 }
     574             : 
     575             :                 //process all RTP infos
     576           6 :                 count = gf_list_count(sess->rtsp_rsp->RTP_Infos);
     577           6 :                 for (i=0; i<count; i++) {
     578           0 :                         info = (GF_RTPInfo*)gf_list_get(sess->rtsp_rsp->RTP_Infos, i);
     579           0 :                         agg_st = rtpin_find_stream(sess->rtpin, NULL, 0, info->url, GF_FALSE);
     580             : 
     581           0 :                         if (!agg_st || (agg_st->rtsp != sess) ) continue;
     582             :                         /*channel is already playing*/
     583           0 :                         if (agg_st->status == RTP_Running) {
     584           0 :                                 gf_rtp_set_info_rtp(agg_st->rtp_ch, info->seq, info->rtp_time, info->ssrc);
     585           0 :                                 agg_st->check_rtp_time = RTP_SET_TIME_RTP;
     586           0 :                                 continue;
     587             :                         }
     588             : 
     589             :                         /*if play/seeking we must send update RTP/NPT link*/
     590           0 :                         if (ch_ctrl->evt.base.type != GF_FEVT_RESUME) {
     591           0 :                                 agg_st->check_rtp_time = RTP_SET_TIME_RTP;
     592             :                         }
     593             :                         /*this is used to discard RTP packets re-sent on resume*/
     594             :                         else {
     595           0 :                                 agg_st->check_rtp_time = RTP_SET_TIME_RTP_SEEK;
     596             :                         }
     597             :                         /* reset the buffers */
     598           0 :                         rtpin_stream_init(agg_st, GF_TRUE);
     599             : 
     600           0 :                         gf_rtp_set_info_rtp(agg_st->rtp_ch, info->seq, info->rtp_time, info->ssrc);
     601           0 :                         agg_st->status = RTP_Running;
     602             : 
     603             :                         /*skip next play command on this channel if aggregated control*/
     604           0 :                         if ((stream != agg_st) && stream && (stream->rtsp->flags & RTSP_AGG_CONTROL) ) agg_st->flags |= RTP_SKIP_NEXT_COM;
     605             : 
     606             : 
     607           0 :                         if (gf_rtp_is_interleaved(agg_st->rtp_ch)) {
     608           0 :                                 gf_rtsp_register_interleave(sess->session,
     609             :                                                             agg_st,
     610           0 :                                                             gf_rtp_get_low_interleave_id(agg_st->rtp_ch),
     611           0 :                                                             gf_rtp_get_hight_interleave_id(agg_st->rtp_ch));
     612             :                         }
     613             :                 }
     614             :                 /*no rtp info (just in case), no time mapped - set to 0 and specify we're not interactive*/
     615           6 :                 if (stream && !i) {
     616           6 :                         stream->current_start = 0.0;
     617           6 :                         stream->check_rtp_time = RTP_SET_TIME_RTP;
     618           6 :                         rtpin_stream_init(stream, GF_TRUE);
     619           6 :                         stream->status = RTP_Running;
     620           6 :                         if (gf_rtp_is_interleaved(stream->rtp_ch)) {
     621           2 :                                 gf_rtsp_register_interleave(sess->session,
     622           2 :                                                             stream, gf_rtp_get_low_interleave_id(stream->rtp_ch), gf_rtp_get_hight_interleave_id(stream->rtp_ch));
     623             :                         }
     624             :                 }
     625           6 :                 if (stream) stream->flags &= ~RTP_SKIP_NEXT_COM;
     626           6 :         } else if (ch_ctrl->evt.base.type == GF_FEVT_PAUSE) {
     627           0 :                 if (stream) {
     628           0 :                         rtpin_rtsp_skip_command(stream);
     629           0 :                         stream->flags &= ~RTP_SKIP_NEXT_COM;
     630             : 
     631             :                 }
     632           6 :         } else if (ch_ctrl->evt.base.type == GF_FEVT_STOP) {
     633           6 :                 sess->rtpin->eos_probe_start = gf_sys_clock();
     634           6 :                 if (stream)
     635           6 :                         stream->flags |= RTP_EOS;
     636             :         }
     637          12 :         gf_free(ch_ctrl);
     638          12 :         com->user_data = NULL;
     639          12 :         return;
     640             : 
     641             : 
     642           0 : err_exit:
     643           0 :         if (stream) {
     644           0 :                 stream->status = RTP_Disconnected;
     645           0 :                 stream->flags |= RTP_EOS;
     646           0 :                 gf_rtsp_reset_aggregation(stream->rtsp->session);
     647           0 :                 stream->check_rtp_time = RTP_SET_TIME_NONE;
     648             :         }
     649           0 :         GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTSP] Error processing user command %s\n", gf_error_to_string(e) ));
     650           0 :         gf_free(ch_ctrl);
     651           0 :         com->user_data = NULL;
     652           0 :         if (sess->flags & RTSP_TCP_FLUSH) {
     653           0 :                 sess->rtpin->eos_probe_start = gf_sys_clock();
     654             :         }
     655             : }
     656             : 
     657             : 
     658          12 : void rtpin_rtsp_usercom_send(GF_RTPInRTSP *sess, GF_RTPInStream *stream, const GF_FilterEvent *evt)
     659             : {
     660             :         RTPIn_StreamControl *ch_ctrl;
     661             :         u32 i;
     662             :         Bool needs_setup = GF_FALSE;
     663             :         GF_RTSPCommand *com;
     664             :         GF_RTSPRange *range;
     665             : 
     666          12 :         switch (evt->base.type) {
     667             :         case GF_FEVT_PLAY:
     668             :         case GF_FEVT_RESUME:
     669             :                 needs_setup = GF_TRUE;
     670             :                 break;
     671             :         case GF_FEVT_PAUSE:
     672             :         case GF_FEVT_STOP:
     673             :                 break;
     674             :         //TODO
     675             :         case GF_FEVT_SET_SPEED:
     676             :         default:
     677             :                 return;
     678             :         }
     679             : 
     680             : 
     681             :         /*we may need to re-setup stream/session*/
     682             :         if (needs_setup) {
     683           6 :                 if (stream->status == RTP_Disconnected) {
     684           0 :                         if (sess->flags & RTSP_AGG_CONTROL) {
     685             :                                 GF_RTPInStream *a_st;
     686           0 :                                 i=0;
     687           0 :                                 while ((a_st = (GF_RTPInStream *)gf_list_enum(sess->rtpin->streams, &i))) {
     688           0 :                                         if (a_st->rtsp != sess) continue;
     689           0 :                                         if (a_st->status == RTP_Disconnected)
     690           0 :                                                 rtpin_rtsp_setup_send(a_st);
     691             :                                 }
     692             :                         } else {
     693           0 :                                 rtpin_rtsp_setup_send(stream);
     694             :                         }
     695             :                 }
     696             :         }
     697             : 
     698          12 :         com     = gf_rtsp_command_new();
     699             :         range = NULL;
     700             : 
     701          12 :         if ( (evt->base.type == GF_FEVT_PLAY) || (evt->base.type == GF_FEVT_RESUME) ) {
     702             : 
     703           6 :                 range = gf_rtsp_range_new();
     704           6 :                 range->start = stream->range_start;
     705           6 :                 range->end = stream->range_end;
     706             : 
     707           6 :                 com->method = gf_strdup(GF_RTSP_PLAY);
     708             : 
     709           6 :                 stream->paused = GF_FALSE;
     710             : 
     711             :                 /*specify pause range on resume - this is not mandatory but most servers need it*/
     712           6 :                 if (evt->base.type == GF_FEVT_RESUME) {
     713           0 :                         range->start = stream->current_start;
     714             : 
     715           0 :                         stream->stat_start_time -= stream->stat_stop_time;
     716           0 :                         stream->stat_start_time += gf_sys_clock();
     717           0 :                         stream->stat_stop_time = 0;
     718             :                 } else {
     719           6 :                         range->start = stream->range_start;
     720           6 :                         if (evt->play.start_range>=0) range->start += evt->play.start_range;
     721           6 :                         range->end = stream->range_start;
     722           6 :                         if (evt->play.end_range >=0) {
     723           6 :                                 range->end += evt->play.end_range;
     724           6 :                                 if (range->end > stream->range_end) range->end = stream->range_end;
     725             :                         }
     726             : 
     727           6 :                         stream->stat_start_time = gf_sys_clock();
     728           6 :                         stream->stat_stop_time = 0;
     729             :                 }
     730             :                 /*if aggregated the command is sent once, so store info at session level*/
     731           6 :                 if (stream->flags & RTP_SKIP_NEXT_COM) {
     732           0 :                         stream->current_start = stream->rtsp->last_range;
     733             :                 } else {
     734           6 :                         stream->rtsp->last_range = range->start;
     735           6 :                         stream->current_start = range->start;
     736             :                 }
     737             :                 /*some RTSP servers don't accept Range=npt:0.0- (for ex, broadcast only...), so skip it if:
     738             :                 - a range was given in initial describe
     739             :                 - the command is not a RESUME
     740             :                 */
     741           6 :                 if (!(stream->flags & RTP_HAS_RANGE) && (evt->base.type != GF_FEVT_RESUME) ) {
     742           0 :                         gf_rtsp_range_del(range);
     743           0 :                         com->Range = NULL;
     744             :                 } else {
     745           6 :                         com->Range = range;
     746             :                 }
     747             : 
     748           6 :                 if (sess->flags & RTSP_AGG_CONTROL)
     749           0 :                         rtpin_rtsp_skip_command(stream);
     750           6 :                 else if (strlen(stream->control))
     751           6 :                         com->ControlString = gf_strdup(stream->control);
     752             : 
     753           6 :                 if (rtpin_rtsp_is_active(stream)) {
     754           0 :                         if (!com->ControlString && stream->control) com->ControlString = gf_strdup(stream->control);
     755             :                 } else {
     756           6 :                         if (com->ControlString) {
     757           6 :                                 gf_free(com->ControlString);
     758           6 :                                 com->ControlString=NULL;
     759             :                         }
     760             :                 }
     761             : 
     762           6 :         } else if (evt->base.type == GF_FEVT_PAUSE) {
     763           0 :                 com->method = gf_strdup(GF_RTSP_PAUSE);
     764           0 :                 if (stream) {
     765           0 :                         range = gf_rtsp_range_new();
     766             :                         /*update current time*/
     767           0 :                         stream->current_start += gf_rtp_get_current_time(stream->rtp_ch);
     768           0 :                         stream->stat_stop_time = gf_sys_clock();
     769           0 :                         range->start = stream->current_start;
     770           0 :                         range->end = -1.0;
     771           0 :                         com->Range = range;
     772             : 
     773           0 :                         if (sess->flags & RTSP_AGG_CONTROL)
     774           0 :                                 rtpin_rtsp_skip_command(stream);
     775           0 :                         else if (strlen(stream->control))
     776           0 :                                 com->ControlString = gf_strdup(stream->control);
     777             : 
     778           0 :                         stream->paused = GF_TRUE;
     779             :                 }
     780             :         }
     781           6 :         else if (evt->base.type == GF_FEVT_STOP) {
     782           6 :                 stream->current_start = 0;
     783           6 :                 stream->stat_stop_time = gf_sys_clock();
     784             : 
     785           6 :                 stream->status = RTP_Connected;
     786           6 :                 rtpin_stream_init(stream, GF_TRUE);
     787             : 
     788             :                 /*if server only support aggregation on pause, skip the command or issue
     789             :                 a teardown if last active stream*/
     790           6 :                 if (stream->rtsp->flags & RTSP_AGG_ONLY) {
     791           0 :                         stream->flags &= ~RTP_SKIP_NEXT_COM;
     792             :                         //remove interleaved
     793           0 :                         if (gf_rtp_is_interleaved(stream->rtp_ch)) {
     794           0 :                                 gf_rtsp_unregister_interleave(stream->rtsp->session, gf_rtp_get_low_interleave_id(stream->rtp_ch));
     795             :                         }
     796             : 
     797           0 :                         if (com) gf_rtsp_command_del(com);
     798           0 :                         if (!rtpin_rtsp_is_active(stream))
     799           0 :                                 rtpin_rtsp_teardown(sess, stream);
     800             :                         return;
     801             :                 }
     802             :                 /* otherwise send a PAUSE on the stream */
     803             :                 else {
     804           6 :                         if (stream->paused) {
     805           0 :                                 if (com) gf_rtsp_command_del(com);
     806             :                                 return;
     807             :                         }
     808           6 :                         range = gf_rtsp_range_new();
     809           6 :                         range->start = 0;
     810           6 :                         range->end = -1;
     811           6 :                         com->method = gf_strdup(GF_RTSP_PAUSE);
     812           6 :                         com->Range = range;
     813             :                         /*only pause the specified stream*/
     814           6 :                         if (stream->control) com->ControlString = gf_strdup(stream->control);
     815             :                 }
     816             :         } else {
     817           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTSP] Unsupported command %s\n", gf_filter_event_name(evt->base.type) ));
     818           0 :                 gf_rtsp_command_del(com);
     819           0 :                 return;
     820             :         }
     821             : 
     822          12 :         ch_ctrl = (RTPIn_StreamControl *)gf_malloc(sizeof(RTPIn_StreamControl));
     823          12 :         ch_ctrl->stream = stream;
     824          12 :         memcpy(&ch_ctrl->evt, evt, sizeof(GF_FilterEvent));
     825          12 :         com->user_data = ch_ctrl;
     826             : 
     827          12 :         rtpin_rtsp_queue_command(sess, stream, com, GF_TRUE);
     828             :         return;
     829             : }
     830             : 
     831             : 
     832             : /*
     833             :                                                 session/channel teardown functions
     834             :                                                                                                                                 */
     835           5 : void rtpin_rtsp_teardown_process(GF_RTPInRTSP *sess, GF_RTSPCommand *com, GF_Err e)
     836             : {
     837           5 :         GF_RTPInStream *stream = (GF_RTPInStream *)com->user_data;
     838           5 :         if (stream) {
     839           0 :                 if (stream->session_id) gf_free(stream->session_id);
     840           0 :                 stream->session_id = NULL;
     841             :         } else {
     842           5 :                 if (sess->session_id) gf_free(sess->session_id);
     843           5 :                 sess->session_id = NULL;
     844             :         }
     845           5 : }
     846             : 
     847           5 : void rtpin_rtsp_teardown(GF_RTPInRTSP *sess, GF_RTPInStream *stream)
     848             : {
     849             :         GF_RTSPCommand *com;
     850             : 
     851             :         /*we need a session id*/
     852           5 :         if (!sess->session_id) return;
     853             :         /*ignore teardown on channels*/
     854           5 :         if ((sess->flags & RTSP_AGG_CONTROL) && stream) return;
     855             : 
     856           5 :         com = gf_rtsp_command_new();
     857           5 :         com->method = gf_strdup(GF_RTSP_TEARDOWN);
     858             :         /*this only works in RTSP2*/
     859           5 :         if (stream && stream->control) {
     860           0 :                 com->ControlString = gf_strdup(stream->control);
     861           0 :                 com->user_data = stream;
     862             :         }
     863             : 
     864           5 :         rtpin_rtsp_queue_command(sess, stream, com, GF_TRUE);
     865             : }
     866             : 
     867             : #endif /*GPAC_DISABLE_STREAMING*/

Generated by: LCOV version 1.13