LCOV - code coverage report
Current view: top level - ietf - rtp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 422 509 82.9 %
Date: 2021-04-29 23:48:07 Functions: 35 35 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-2012
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / IETF RTP/RTSP/SDP sub-project
       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 <gpac/internal/ietf_dev.h>
      27             : 
      28             : #ifndef GPAC_DISABLE_STREAMING
      29             : 
      30             : #define MAX_RTP_SN      0x10000
      31             : 
      32             : 
      33             : GF_EXPORT
      34          58 : GF_RTPChannel *gf_rtp_new()
      35             : {
      36             :         GF_RTPChannel *tmp;
      37          58 :         GF_SAFEALLOC(tmp, GF_RTPChannel);
      38          58 :         if (!tmp)
      39             :                 return NULL;
      40          58 :         tmp->first_SR = 1;
      41          58 :         tmp->SSRC = gf_rand();
      42          58 :         tmp->bs_r = gf_bs_new("d", 1, GF_BITSTREAM_READ);
      43          58 :         tmp->bs_w = gf_bs_new("d", 1, GF_BITSTREAM_WRITE);
      44          58 :         return tmp;
      45             : }
      46             : 
      47             : GF_EXPORT
      48          58 : void gf_rtp_del(GF_RTPChannel *ch)
      49             : {
      50          58 :         if (!ch) return;
      51          58 :         if (ch->rtp) gf_sk_del(ch->rtp);
      52          58 :         if (ch->rtcp) gf_sk_del(ch->rtcp);
      53          58 :         if (ch->net_info.source) gf_free(ch->net_info.source);
      54          58 :         if (ch->net_info.destination) gf_free(ch->net_info.destination);
      55          58 :         if (ch->net_info.Profile) gf_free(ch->net_info.Profile);
      56          58 :         if (ch->po) gf_rtp_reorderer_del(ch->po);
      57          58 :         if (ch->send_buffer) gf_free(ch->send_buffer);
      58             : 
      59          58 :         if (ch->CName) gf_free(ch->CName);
      60          58 :         if (ch->s_name) gf_free(ch->s_name);
      61          58 :         if (ch->s_email) gf_free(ch->s_email);
      62          58 :         if (ch->s_location) gf_free(ch->s_location);
      63          58 :         if (ch->s_phone) gf_free(ch->s_phone);
      64          58 :         if (ch->s_tool) gf_free(ch->s_tool);
      65          58 :         if (ch->s_note) gf_free(ch->s_note);
      66          58 :         if (ch->s_priv) gf_free(ch->s_priv);
      67          58 :         if (ch->bs_r) gf_bs_del(ch->bs_r);
      68          58 :         if (ch->bs_w) gf_bs_del(ch->bs_w);
      69             :         memset(ch, 0, sizeof(GF_RTPChannel));
      70          58 :         gf_free(ch);
      71             : }
      72             : 
      73             : 
      74             : GF_EXPORT
      75          66 : GF_Err gf_rtp_setup_transport(GF_RTPChannel *ch, GF_RTSPTransport *trans_info, const char *remote_address)
      76             : {
      77          66 :         if (!ch || !trans_info) return GF_BAD_PARAM;
      78             :         //assert we have at least ONE source ID
      79          66 :         if (!trans_info->source && !remote_address) return GF_BAD_PARAM;
      80             : 
      81          66 :         if (ch->net_info.destination) gf_free(ch->net_info.destination);
      82          66 :         ch->net_info.destination = NULL;
      83          66 :         if (ch->net_info.Profile) gf_free(ch->net_info.Profile);
      84          66 :         ch->net_info.Profile = NULL;
      85          66 :         if (ch->net_info.source) gf_free(ch->net_info.source);
      86          66 :         ch->net_info.source = NULL;
      87          66 :         memcpy(&ch->net_info, trans_info, sizeof(GF_RTSPTransport));
      88             : 
      89          66 :         if (trans_info->destination)
      90          39 :                 ch->net_info.destination = gf_strdup(trans_info->destination);
      91             : 
      92          66 :         if (trans_info->Profile)
      93          66 :                 ch->net_info.Profile = gf_strdup(trans_info->Profile);
      94             : 
      95          66 :         if (!ch->net_info.IsUnicast && trans_info->destination) {
      96             :                 assert( trans_info->destination );
      97           4 :                 ch->net_info.source = gf_strdup(trans_info->destination);
      98           4 :                 if (ch->net_info.client_port_first) {
      99           1 :                         ch->net_info.port_first = ch->net_info.client_port_first;
     100           1 :                         ch->net_info.port_last = ch->net_info.client_port_last;
     101             :                 }
     102          62 :         } else if (trans_info->source) {
     103          57 :                 ch->net_info.source = gf_strdup(trans_info->source);
     104             :         } else {
     105           5 :                 ch->net_info.source = gf_strdup(remote_address);
     106             :         }
     107          66 :         if (trans_info->SSRC) {
     108          43 :                 if (trans_info->is_sender) {
     109           6 :                         ch->SSRC = trans_info->SSRC;
     110             :                 } else {
     111          37 :                         ch->SenderSSRC = trans_info->SSRC;
     112             :                 }
     113             :         }
     114             :         //check we REALLY have unicast or multicast
     115          66 :         if (gf_sk_is_multicast_address(ch->net_info.source) && ch->net_info.IsUnicast) return GF_SERVICE_ERROR;
     116          66 :         return GF_OK;
     117             : }
     118             : 
     119             : 
     120             : GF_EXPORT
     121          32 : void gf_rtp_reset_buffers(GF_RTPChannel *ch)
     122             : {
     123          32 :         if (ch->rtp) gf_sk_reset(ch->rtp);
     124          32 :         if (ch->rtcp) gf_sk_reset(ch->rtcp);
     125          32 :         if (ch->po) gf_rtp_reorderer_reset(ch->po);
     126          32 :         ch->first_SR = 1;
     127          32 : }
     128             : 
     129             : GF_EXPORT
     130           1 : void gf_rtp_reset_ssrc(GF_RTPChannel *ch)
     131             : {
     132           1 :         if (ch) ch->SenderSSRC = 0;
     133           1 : }
     134             : 
     135             : GF_EXPORT
     136           3 : void gf_rtp_enable_nat_keepalive(GF_RTPChannel *ch, u32 nat_timeout)
     137             : {
     138           3 :         if (ch) {
     139           2 :                 ch->nat_keepalive_time_period = nat_timeout;
     140           2 :                 ch->last_nat_keepalive_time = 0;
     141             :         }
     142           3 : }
     143             : 
     144             : 
     145             : 
     146             : GF_EXPORT
     147          13 : GF_Err gf_rtp_set_info_rtp(GF_RTPChannel *ch, u32 seq_num, u32 rtp_time, u32 ssrc)
     148             : {
     149          13 :         if (!ch) return GF_BAD_PARAM;
     150          13 :         ch->CurrentTime = ch->rtp_time = seq_num ? (1 + rtp_time) : 0;
     151          13 :         ch->last_pck_sn = 0;
     152          13 :         ch->rtp_first_SN = seq_num;
     153          13 :         ch->num_sn_loops = 0;
     154             :         //reset RTCP
     155          13 :         ch->ntp_init = 0;
     156          13 :         ch->first_SR = 1;
     157          13 :         if (ssrc) ch->SenderSSRC = ssrc;
     158          13 :         ch->total_pck = ch->total_bytes = ch->last_num_pck_rcv = ch->last_num_pck_expected = ch->last_num_pck_loss = ch->tot_num_pck_rcv = ch->tot_num_pck_expected = ch->rtcp_bytes_sent = 0;
     159          13 :         return GF_OK;
     160             : }
     161             : 
     162             : GF_EXPORT
     163           1 : GF_Err gf_rtp_stop(GF_RTPChannel *ch)
     164             : {
     165           1 :         if (!ch) return GF_BAD_PARAM;
     166           0 :         if (ch->rtp) gf_sk_del(ch->rtp);
     167           0 :         ch->rtp = NULL;
     168           0 :         if (ch->rtcp) gf_sk_del(ch->rtcp);
     169           0 :         ch->rtcp = NULL;
     170           0 :         if (ch->po) gf_rtp_reorderer_del(ch->po);
     171           0 :         ch->po = NULL;
     172           0 :         return GF_OK;
     173             : }
     174             : 
     175             : GF_EXPORT
     176          57 : GF_Err gf_rtp_initialize(GF_RTPChannel *ch, u32 UDPBufferSize, Bool IsSource, u32 PathMTU, u32 ReorederingSize, u32 MaxReorderDelay, char *local_ip)
     177             : {
     178             :         u16 port;
     179             :         GF_Err e;
     180             : 
     181          57 :         if (!ch || (IsSource && !PathMTU)) return GF_BAD_PARAM;
     182             : 
     183          57 :         if (ch->rtp) gf_sk_del(ch->rtp);
     184          57 :         ch->rtp = NULL;
     185          57 :         if (ch->rtcp) gf_sk_del(ch->rtcp);
     186          57 :         ch->rtcp = NULL;
     187          57 :         if (ch->po) gf_rtp_reorderer_del(ch->po);
     188          57 :         ch->po = NULL;
     189             : 
     190          57 :         ch->CurrentTime = 0;
     191          57 :         ch->rtp_time = 0;
     192             : 
     193             :         //create sockets for RTP/AVP profile only
     194         114 :         if (ch->net_info.Profile &&
     195          57 :                 ( !stricmp(ch->net_info.Profile, GF_RTSP_PROFILE_RTP_AVP)
     196           2 :                   || !stricmp(ch->net_info.Profile, "RTP/AVP/UDP")
     197           2 :                   || !stricmp(ch->net_info.Profile, "RTP/SAVP")
     198             :                 )
     199             :            ) {
     200             :                 //destination MUST be specified for unicast
     201          55 :                 if (IsSource && ch->net_info.IsUnicast && !ch->net_info.destination) return GF_BAD_PARAM;
     202             : 
     203             :                 /* forcing unicast when the address is not a multicast */
     204          55 :                 if (!ch->net_info.IsUnicast) {
     205           4 :                         if (IsSource) {
     206           2 :                                 if (ch->net_info.destination && !gf_sk_is_multicast_address(ch->net_info.destination)) {
     207           0 :                                         ch->net_info.IsUnicast = GF_TRUE;
     208             :                                 }
     209             :                         } else {
     210           2 :                                 if (ch->net_info.source && !gf_sk_is_multicast_address(ch->net_info.source)) {
     211           1 :                                         ch->net_info.IsUnicast = GF_TRUE;
     212             :                                 }
     213             :                         }
     214             :                 }
     215             :                 //
     216             :                 //      RTP
     217             :                 //
     218          55 :                 ch->rtp = gf_sk_new(GF_SOCK_TYPE_UDP);
     219          55 :                 if (!ch->rtp) return GF_IP_NETWORK_FAILURE;
     220          55 :                 if (ch->net_info.IsUnicast) {
     221             :                         //if client, bind and connect the socket
     222          52 :                         if (!IsSource) {
     223          18 :                                 port = ch->net_info.port_first;
     224          18 :                                 if (!port) port = ch->net_info.client_port_first;
     225             :                                 /*if a destination address was given (rtsd) use it*/
     226          18 :                                 if (!local_ip && ch->net_info.destination) local_ip = ch->net_info.destination;
     227             : 
     228          18 :                                 e = gf_sk_bind(ch->rtp, local_ip, ch->net_info.client_port_first, ch->net_info.source, port, GF_SOCK_REUSE_PORT);
     229          18 :                                 if (e) return e;
     230             :                         }
     231             :                         //else bind and set remote destination
     232             :                         else {
     233          34 :                                 if (!ch->net_info.port_first) ch->net_info.port_first = ch->net_info.client_port_first;
     234          34 :                                 e = gf_sk_bind(ch->rtp, local_ip,ch->net_info.port_first, ch->net_info.destination, ch->net_info.client_port_first, GF_SOCK_REUSE_PORT | GF_SOCK_FAKE_BIND);
     235          34 :                                 if (e) return e;
     236             :                         }
     237             :                 } else {
     238             :                         //Bind to multicast (auto-join the group).
     239             :                         //we do not bind the socket if this is a source-only channel because some servers
     240             :                         //don't like that on local loop ...
     241           3 :                         e = gf_sk_setup_multicast(ch->rtp, ch->net_info.source, ch->net_info.port_first, ch->net_info.TTL, GF_FALSE, local_ip);
     242           3 :                         if (e) return e;
     243             :                 }
     244          55 :                 if (UDPBufferSize) gf_sk_set_buffer_size(ch->rtp, IsSource, UDPBufferSize);
     245             : 
     246             :                 //create re-ordering queue for UDP only, and receive
     247          55 :                 if (ReorederingSize && !IsSource) {
     248          19 :                         if (!MaxReorderDelay) MaxReorderDelay = 200;
     249          19 :                         ch->po = gf_rtp_reorderer_new(ReorederingSize, MaxReorderDelay);
     250             :                 }
     251             : 
     252             :                 //
     253             :                 //      RTCP
     254             :                 //
     255          55 :                 ch->rtcp = gf_sk_new(GF_SOCK_TYPE_UDP);
     256          55 :                 if (!ch->rtcp) return GF_IP_NETWORK_FAILURE;
     257          55 :                 if (ch->net_info.IsUnicast) {
     258          52 :                         if (!IsSource) {
     259          18 :                                 port = ch->net_info.port_last;
     260          18 :                                 if (!port) port = ch->net_info.client_port_last;
     261             :                                 /*if a destination address was given (rtsd) use it*/
     262          18 :                                 if (!local_ip && ch->net_info.destination) local_ip = ch->net_info.destination;
     263             : 
     264          18 :                                 e = gf_sk_bind(ch->rtcp, local_ip, ch->net_info.client_port_last, ch->net_info.source, port, GF_SOCK_REUSE_PORT);
     265          18 :                                 if (e) return e;
     266             :                         } else {
     267          34 :                                 e = gf_sk_bind(ch->rtcp, local_ip, ch->net_info.port_last, ch->net_info.destination, ch->net_info.client_port_last, GF_SOCK_REUSE_PORT | GF_SOCK_FAKE_BIND);
     268          34 :                                 if (e) return e;
     269             :                         }
     270             :                 } else {
     271           3 :                         if (!ch->net_info.port_last) ch->net_info.port_last = ch->net_info.client_port_last;
     272             :                         //Bind to multicast (auto-join the group)
     273           3 :                         e = gf_sk_setup_multicast(ch->rtcp, ch->net_info.source, ch->net_info.port_last, ch->net_info.TTL, GF_FALSE, local_ip);
     274           3 :                         if (e) return e;
     275             :                 }
     276             :         }
     277             : 
     278          57 :         if (IsSource) {
     279          37 :                 if (ch->send_buffer) gf_free(ch->send_buffer);
     280          37 :                 ch->send_buffer_size = PathMTU + 12;
     281          37 :                 ch->send_buffer = (char *) gf_malloc(sizeof(char) * ch->send_buffer_size);
     282             :         }
     283             : 
     284             :         //format CNAME if not done yet
     285          57 :         if (!ch->CName) {
     286             :                 //this is the real CName setup
     287          57 :                 if (!ch->rtp) {
     288           2 :                         ch->CName = gf_strdup("mpeg4rtp");
     289             :                 } else {
     290             :                         char name[GF_MAX_IP_NAME_LEN];
     291             : 
     292             :                         size_t start;
     293          55 :                         gf_get_user_name(name);
     294          55 :                         if (strlen(name)) strcat(name, "@");
     295          55 :                         start = strlen(name);
     296             :                         //get host IP or loopback if error
     297          55 :                         if (gf_sk_get_local_ip(ch->rtp, name+start) != GF_OK) strcpy(name+start, "127.0.0.1");
     298          55 :                         ch->CName = gf_strdup(name);
     299             :                 }
     300             :         }
     301             : 
     302             : #ifndef GPAC_DISABLE_LOG
     303          57 :         if (gf_log_tool_level_on(GF_LOG_RTP, GF_LOG_DEBUG))  {
     304           0 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] Packet Log Format: SSRC SequenceNumber TimeStamp NTP@recvTime deviance, Jiter, PckLost PckTotal BytesTotal\n"));
     305             :         }
     306             : #endif
     307             : 
     308             :         return GF_OK;
     309             : }
     310             : 
     311             : /*get the UTC time expressed in RTP timescale*/
     312         755 : u32 gf_rtp_channel_time(GF_RTPChannel *ch)
     313             : {
     314             :         u32 sec, frac, res;
     315         755 :         gf_net_get_ntp(&sec, &frac);
     316         755 :         res = ( (u32) ( (frac>>26)*ch->TimeScale) ) >> 6;
     317         755 :         res += ch->TimeScale*(sec - ch->ntp_init);
     318         755 :         return (u32) res;
     319             : }
     320             : 
     321        1653 : u32 gf_rtp_get_report_time()
     322             : {
     323             :         u32 sec, frac;
     324        1715 :         gf_net_get_ntp(&sec, &frac);
     325             :         /*in units of 1/65536 seconds*/
     326        1715 :         return (u32) ( (frac>>16) + 0x10000L*sec );
     327             : }
     328             : 
     329             : 
     330          62 : void gf_rtp_get_next_report_time(GF_RTPChannel *ch)
     331             : {
     332             :         Double d;
     333             : 
     334             :         /*offset between .5 and 1.5 sec*/
     335          62 :         d = 0.5 + ((Double) gf_rand()) / ((Double) RAND_MAX);
     336             :         /*of a minimal 5sec interval expressed in 1/65536 of a sec*/
     337          62 :         d = 5.0 * d * 65536;
     338             :         /*we should estimate bandwidth sharing too*/
     339          62 :         ch->next_report_time = gf_rtp_get_report_time() + (u32) d;
     340          62 : }
     341             : 
     342             : GF_EXPORT
     343          39 : u32 gf_rtp_read_flush(GF_RTPChannel *ch, u8 *buffer, u32 buffer_size)
     344             : {
     345             :         char *pck;
     346          39 :         u32 res = 0;
     347          39 :         if (!ch->po) return 0;
     348             : 
     349             :         //pck queue may need to be flushed
     350          38 :         pck = (char *) gf_rtp_reorderer_get(ch->po, &res, GF_TRUE);
     351          38 :         if (pck) {
     352          19 :                 memcpy(buffer, pck, res);
     353          19 :                 gf_free(pck);
     354             :         }
     355          38 :         return res;
     356             : }
     357             : 
     358             : GF_EXPORT
     359           7 : u32 gf_rtp_flush_rtp(GF_RTPChannel *ch, u8 *buffer, u32 buffer_size)
     360             : {
     361             :         u32 res;
     362             :         char *pck;
     363             : 
     364             :         //only if the socket exist (otherwise RTSP interleaved channel)
     365           7 :         if (!ch || !ch->rtp || !ch->po) return 0;
     366             : 
     367             :         //pck queue may need to be flushed
     368           6 :         pck = (char *) gf_rtp_reorderer_get(ch->po, &res, GF_FALSE);
     369           6 :         if (pck) {
     370           0 :                 memcpy(buffer, pck, res);
     371           0 :                 gf_free(pck);
     372           0 :                 return res;
     373             :         }
     374             :         return 0;
     375             : }
     376             : 
     377             : GF_EXPORT
     378         742 : u32 gf_rtp_read_rtp(GF_RTPChannel *ch, u8 *buffer, u32 buffer_size)
     379             : {
     380             :         GF_Err e;
     381             :         u32 seq_num, res;
     382             : 
     383             :         //only if the socket exist (otherwise RTSP interleaved channel)
     384         742 :         if (!ch || !ch->rtp) return 0;
     385             : 
     386         742 :         if (ch->no_select) {
     387           0 :                 e = gf_sk_receive_no_select(ch->rtp, buffer, buffer_size, &res);
     388             :         } else {
     389         742 :                 e = gf_sk_receive(ch->rtp, buffer, buffer_size, &res);
     390             :         }
     391         742 :         if (!res || e || (res < 12)) {
     392             :                 assert(res==0);
     393           0 :                 res = 0;
     394             :         }
     395         742 :         if (res) {
     396         742 :                 ch->total_bytes+=res;
     397         742 :                 ch->total_pck++;
     398             :         }
     399             :         //add the packet to our Queue if any
     400         742 :         if (ch->po) {
     401             :                 char *pck;
     402         742 :                 if (res) {
     403         742 :                         seq_num = ((((u32)buffer[2]) << 8) & 0xFF00) | (buffer[3] & 0xFF);
     404         742 :                         gf_rtp_reorderer_add(ch->po, (void *) buffer, res, seq_num);
     405             :                 }
     406             : 
     407             :                 //pck queue may need to be flushed
     408         742 :                 pck = (char *) gf_rtp_reorderer_get(ch->po, &res, GF_FALSE);
     409         742 :                 if (pck) {
     410         723 :                         memcpy(buffer, pck, res);
     411         723 :                         gf_free(pck);
     412             :                 }
     413             :         }
     414             :         /*monitor keep-alive period*/
     415         742 :         if (ch->nat_keepalive_time_period && !ch->send_interleave) {
     416          32 :                 u32 now = gf_sys_clock();
     417          32 :                 if (res) {
     418          30 :                         ch->last_nat_keepalive_time = now;
     419             :                 } else {
     420           2 :                         if (now - ch->last_nat_keepalive_time >= ch->nat_keepalive_time_period) {
     421             :                                 char rtp_nat[12];
     422           0 :                                 rtp_nat[0] = (u8) 0xC0;
     423           0 :                                 rtp_nat[1] = ch->PayloadType;
     424           0 :                                 rtp_nat[2] = (ch->last_pck_sn>>8)&0xFF;
     425           0 :                                 rtp_nat[3] = (ch->last_pck_sn)&0xFF;
     426           0 :                                 rtp_nat[4] = (ch->last_pck_ts>>24)&0xFF;
     427           0 :                                 rtp_nat[5] = (ch->last_pck_ts>>16)&0xFF;
     428           0 :                                 rtp_nat[6] = (ch->last_pck_ts>>8)&0xFF;
     429           0 :                                 rtp_nat[7] = (ch->last_pck_ts)&0xFF;
     430           0 :                                 rtp_nat[8] = (ch->SenderSSRC>>24)&0xFF;
     431           0 :                                 rtp_nat[9] = (ch->SenderSSRC>>16)&0xFF;
     432           0 :                                 rtp_nat[10] = (ch->SenderSSRC>>8)&0xFF;
     433           0 :                                 rtp_nat[11] = (ch->SenderSSRC)&0xFF;
     434           0 :                                 e = gf_sk_send(ch->rtp, rtp_nat, 12);
     435           0 :                                 if (e) {
     436           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP] Error sending NAT keep-alive packet: %s - disabling NAT\n", gf_error_to_string(e) ));
     437           0 :                                         ch->nat_keepalive_time_period = 0;
     438             :                                 } else {
     439           0 :                                         GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] Sending NAT keep-alive packet - response %s\n", gf_error_to_string(e) ));
     440             :                                 }
     441           0 :                                 ch->last_nat_keepalive_time = now;
     442             :                         }
     443             :                 }
     444             :         }
     445         742 :         return res;
     446             : }
     447             : 
     448             : 
     449             : GF_EXPORT
     450         755 : GF_Err gf_rtp_decode_rtp(GF_RTPChannel *ch, u8 *pck, u32 pck_size, GF_RTPHeader *rtp_hdr, u32 *PayloadStart)
     451             : {
     452             :         GF_Err e;
     453             :         s32 deviance, delta;
     454             :         u32 CurrSeq, LastSeq;
     455             :         u32 ntp, lost, low16;
     456             : 
     457         755 :         if (!rtp_hdr) return GF_BAD_PARAM;
     458             :         e = GF_OK;
     459             : 
     460         755 :         gf_bs_reassign_buffer(ch->bs_r, pck, pck_size);
     461             :         //we need to uncompress the RTP header
     462         755 :         rtp_hdr->Version = gf_bs_read_int(ch->bs_r, 2);
     463         755 :         if (rtp_hdr->Version != 2) return GF_NOT_SUPPORTED;
     464             : 
     465         755 :         rtp_hdr->Padding = gf_bs_read_int(ch->bs_r, 1);
     466         755 :         rtp_hdr->Extension = gf_bs_read_int(ch->bs_r, 1);
     467         755 :         rtp_hdr->CSRCCount = gf_bs_read_int(ch->bs_r, 4);
     468         755 :         rtp_hdr->Marker = gf_bs_read_int(ch->bs_r, 1);
     469         755 :         rtp_hdr->PayloadType = gf_bs_read_int(ch->bs_r, 7);
     470             : 
     471             :         /*we don't support multiple CSRC now. Only one source (the server) is allowed*/
     472         755 :         if (rtp_hdr->CSRCCount) return GF_NOT_SUPPORTED;
     473             :         /*SeqNum*/
     474         755 :         rtp_hdr->SequenceNumber = gf_bs_read_u16(ch->bs_r);
     475             :         /*TS*/
     476         755 :         rtp_hdr->TimeStamp = gf_bs_read_u32(ch->bs_r);
     477             :         /*SSRC*/
     478         755 :         rtp_hdr->SSRC = gf_bs_read_u32(ch->bs_r);
     479             : 
     480             :         /*update RTP time if we didn't get the info*/
     481         755 :         if (!ch->rtp_time) {
     482          20 :                 ch->rtp_time = 1 + rtp_hdr->TimeStamp;
     483          20 :                 ch->rtp_first_SN = rtp_hdr->SequenceNumber;
     484          20 :                 ch->num_sn_loops = 0;
     485             :         }
     486         755 :         if (ch->first_SR && !ch->SenderSSRC && rtp_hdr->SSRC) {
     487           1 :                 ch->SenderSSRC = rtp_hdr->SSRC;
     488           1 :                 GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTP] Assigning SSRC to %d because none was specified through SDP/RTSP\n", ch->SenderSSRC));
     489             :         }
     490             : 
     491         755 :         if (!ch->ntp_init && ch->SenderSSRC && (ch->SenderSSRC != rtp_hdr->SSRC) ) {
     492           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[RTP] SSRC mismatch: %d vs %d\n", rtp_hdr->SSRC, ch->SenderSSRC));
     493             :                 return GF_IP_NETWORK_EMPTY;
     494             :         }
     495             : 
     496             : 
     497             :         /*RTP specs annexe A.8*/
     498         755 :         if (!ch->ntp_init) {
     499          20 :                 gf_net_get_ntp(&ch->ntp_init, &lost);
     500          20 :                 ch->last_pck_sn = (u32) rtp_hdr->SequenceNumber-1;
     501             :         }
     502             :         /*this is a loop in SN - add it*/
     503         755 :         if ( (ch->last_pck_sn + 1 > rtp_hdr->SequenceNumber)
     504           0 :                 && (rtp_hdr->SequenceNumber >= ch->last_pck_sn + MAX_RTP_SN/2)) {
     505           0 :                 ch->num_sn_loops += 1;
     506             :         }
     507             : 
     508         755 :         if (ch->last_SR_rtp_time) {
     509             :                 s64 diff_sec;
     510         705 :                 u32 sec = ch->last_SR_NTP_sec;
     511             :                 s64 frac;
     512             : 
     513         705 :                 frac = (s64) rtp_hdr->TimeStamp;
     514         705 :                 frac -= (s64) ch->last_SR_rtp_time;
     515         705 :                 if (frac<0) frac += 0xFFFFFFFF;
     516         705 :                 diff_sec = frac / ch->TimeScale;
     517             : 
     518         705 :                 frac -= diff_sec*ch->TimeScale;
     519         705 :                 frac *= 0xFFFFFFFF;
     520         705 :                 frac /= ch->TimeScale;
     521         705 :                 frac += ch->last_SR_NTP_frac;
     522         705 :                 if (frac>0xFFFFFFFF) {
     523         313 :                         sec += 1;
     524         313 :                         frac -= 0xFFFFFFFF;
     525             :                 }
     526         705 :                 rtp_hdr->recomputed_ntp_ts = sec + (s32) diff_sec;
     527         705 :                 rtp_hdr->recomputed_ntp_ts <<= 32;
     528         705 :                 rtp_hdr->recomputed_ntp_ts |= frac;
     529             :         }
     530             : 
     531         755 :         ntp = gf_rtp_channel_time(ch);
     532         755 :         deviance = ntp - rtp_hdr->TimeStamp;
     533         755 :         delta = deviance - ch->last_deviance;
     534         755 :         ch->last_deviance = deviance;
     535             : 
     536         755 :         if (delta < 0) delta = -delta;
     537         755 :         ch->Jitter += delta - ( (ch->Jitter + 8) >> 4);
     538             : 
     539         755 :         lost = 0;
     540         755 :         LastSeq = ch->last_pck_sn;
     541         755 :         CurrSeq = (u32) rtp_hdr->SequenceNumber;
     542         755 :         ch->packet_loss = GF_FALSE;
     543             :         /*next sequential pck*/
     544         755 :         if ( ( (LastSeq + 1) & 0xffff ) == CurrSeq ) {
     545         755 :                 ch->last_num_pck_rcv += 1;
     546         755 :                 ch->last_num_pck_expected += 1;
     547             :         }
     548             :         /*repeated pck*/
     549           0 :         else if ( (LastSeq & 0xffff ) == CurrSeq ) {
     550           0 :                 ch->last_num_pck_rcv += 1;
     551             :         }
     552             :         /*drop pck*/
     553             :         else {
     554             :                 low16 = LastSeq & 0xffff;
     555           0 :                 if ( CurrSeq > low16 )
     556           0 :                         lost = CurrSeq - low16;
     557             :                 else
     558           0 :                         lost = 0xffff - low16 + CurrSeq + 1;
     559             : 
     560           0 :                 ch->last_num_pck_expected += lost;
     561           0 :                 ch->last_num_pck_rcv += 1;
     562           0 :                 ch->last_num_pck_loss += lost;
     563           0 :                 ch->packet_loss = GF_TRUE;
     564             :         }
     565         755 :         ch->last_pck_sn = CurrSeq;
     566             : 
     567             : #ifndef GPAC_DISABLE_LOG
     568         755 :         if (gf_log_tool_level_on(GF_LOG_RTP, GF_LOG_DEBUG))  {
     569           0 :                 ch->total_bytes += pck_size-12;
     570             : 
     571           0 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP]\t%d\t%d\t%u\t%d\t%d\t%d\t%d\t%d\t%d\n",
     572             :                                                   ch->SenderSSRC,
     573             :                                                   rtp_hdr->SequenceNumber,
     574             :                                                   rtp_hdr->TimeStamp,
     575             :                                                   ntp,
     576             :                                                   delta,
     577             :                                                   ch->Jitter >> 4,
     578             :                                                   lost,
     579             :                                                   ch->total_pck,
     580             :                                                   ch->total_bytes
     581             :                                                  ));
     582             :         }
     583             : #endif
     584             : 
     585             :         //we work with no CSRC so payload offset is always 12
     586         755 :         *PayloadStart = 12;
     587             : 
     588         755 :         if (rtp_hdr->Extension) {
     589             :                 u16 ext_size;
     590           0 :                 char *payl = pck + *PayloadStart;
     591           0 :                 ext_size = payl[2];
     592           0 :                 ext_size <<= 8;
     593           0 :                 ext_size |= payl[3];
     594           0 :                 *PayloadStart += 4 + (ext_size * 4);
     595             :         }
     596             : 
     597             :         //store the time
     598         755 :         ch->CurrentTime = rtp_hdr->TimeStamp;
     599         755 :         return e;
     600             : }
     601             : 
     602             : 
     603             : GF_EXPORT
     604         168 : Double gf_rtp_get_current_time(GF_RTPChannel *ch)
     605             : {
     606             :         Double ret;
     607         168 :         if (!ch || !ch->rtp_time) return 0.0;
     608         168 :         ret = (Double) ch->CurrentTime;
     609         168 :         ret -= (Double) (ch->rtp_time-1);
     610         168 :         ret /= ch->TimeScale;
     611         168 :         return ret;
     612             : }
     613             : 
     614             : 
     615             : 
     616             : 
     617             : 
     618             : 
     619             : GF_EXPORT
     620         892 : GF_Err gf_rtp_send_packet(GF_RTPChannel *ch, GF_RTPHeader *rtp_hdr, u8 *pck, u32 pck_size, Bool fast_send)
     621             : {
     622             :         GF_Err e;
     623             :         u32 i, Start;
     624             :         char *hdr = NULL;
     625             : 
     626         892 :         if (!ch || !rtp_hdr
     627         892 :                 || !ch->send_buffer
     628         892 :                 || !pck
     629         892 :                 || (rtp_hdr->CSRCCount > 15)) return GF_BAD_PARAM;
     630             : 
     631         892 :         if (rtp_hdr->CSRCCount) fast_send = GF_FALSE;
     632             : 
     633         892 :         if (12 + pck_size + 4*rtp_hdr->CSRCCount > ch->send_buffer_size)
     634             :                 return GF_IO_ERR;
     635             : 
     636         892 :         if (fast_send) {
     637         892 :                 hdr = pck - 12;
     638         892 :                 gf_bs_reassign_buffer(ch->bs_w, hdr, 12);
     639             :         } else {
     640           0 :                 gf_bs_reassign_buffer(ch->bs_w, ch->send_buffer, ch->send_buffer_size);
     641             :         }
     642             :         //write header
     643         892 :         gf_bs_write_int(ch->bs_w, rtp_hdr->Version, 2);
     644         892 :         gf_bs_write_int(ch->bs_w, rtp_hdr->Padding, 1);
     645         892 :         gf_bs_write_int(ch->bs_w, rtp_hdr->Extension, 1);
     646         892 :         gf_bs_write_int(ch->bs_w, rtp_hdr->CSRCCount, 4);
     647         892 :         gf_bs_write_int(ch->bs_w, rtp_hdr->Marker, 1);
     648         892 :         gf_bs_write_int(ch->bs_w, rtp_hdr->PayloadType, 7);
     649         892 :         gf_bs_write_u16(ch->bs_w, rtp_hdr->SequenceNumber);
     650         892 :         gf_bs_write_u32(ch->bs_w, rtp_hdr->TimeStamp);
     651         892 :         gf_bs_write_u32(ch->bs_w, ch->SSRC);
     652             : 
     653         892 :         for (i=0; i<rtp_hdr->CSRCCount; i++) {
     654           0 :                 gf_bs_write_u32(ch->bs_w, rtp_hdr->CSRC[i]);
     655             :         }
     656             :         //nb: RTP header is always aligned
     657         892 :         Start = (u32) gf_bs_get_position(ch->bs_w);
     658             : 
     659         892 :         if (ch->send_interleave) {
     660          13 :                 if (fast_send) {
     661          13 :                         e = ch->send_interleave(ch->interleave_cbk1, ch->interleave_cbk2, GF_FALSE, hdr, pck_size+12);
     662             :                 } else {
     663           0 :                         memcpy(ch->send_buffer + Start, pck, pck_size);
     664           0 :                         e = ch->send_interleave(ch->interleave_cbk1, ch->interleave_cbk2, GF_FALSE, ch->send_buffer, Start + pck_size);
     665             :                 }
     666             :         }
     667             :         //copy payload
     668         879 :         else if (fast_send) {
     669         879 :                 e = gf_sk_send(ch->rtp, hdr, pck_size+12);
     670             :         } else {
     671           0 :                 memcpy(ch->send_buffer + Start, pck, pck_size);
     672           0 :                 e = gf_sk_send(ch->rtp, ch->send_buffer, Start + pck_size);
     673             :         }
     674         892 :         if (e) return e;
     675             : 
     676             :         //Update RTCP for sender reports
     677         892 :         ch->pck_sent_since_last_sr += 1;
     678         892 :         if (ch->first_SR) {
     679             :                 //get a new report time
     680          23 :                 gf_rtp_get_next_report_time(ch);
     681          23 :                 ch->num_payload_bytes = 0;
     682          23 :                 ch->num_pck_sent = 0;
     683          23 :                 ch->first_SR = 0;
     684             :         }
     685             : 
     686         892 :         ch->num_payload_bytes += pck_size;
     687         892 :         ch->num_pck_sent += 1;
     688             :         //store timing
     689         892 :         ch->last_pck_ts = rtp_hdr->TimeStamp;
     690         892 :         gf_net_get_ntp(&ch->last_pck_ntp_sec, &ch->last_pck_ntp_frac);
     691             : 
     692         892 :         if (!ch->no_auto_rtcp) gf_rtp_send_rtcp_report(ch);
     693             :         return GF_OK;
     694             : }
     695             : 
     696             : GF_EXPORT
     697           6 : u32 gf_rtp_is_unicast(GF_RTPChannel *ch)
     698             : {
     699           6 :         if (!ch) return 0;
     700           6 :         return ch->net_info.IsUnicast;
     701             : }
     702             : 
     703             : GF_EXPORT
     704          23 : u32 gf_rtp_is_interleaved(GF_RTPChannel *ch)
     705             : {
     706          23 :         if (!ch || !ch->net_info.Profile) return 0;
     707          23 :         return ch->net_info.IsInterleaved;
     708             : }
     709             : 
     710             : GF_EXPORT
     711         101 : u32 gf_rtp_get_clockrate(GF_RTPChannel *ch)
     712             : {
     713         101 :         if (!ch || !ch->TimeScale) return 0;
     714         101 :         return ch->TimeScale;
     715             : }
     716             : 
     717             : #if 0 //unused
     718             : u32 gf_rtp_is_active(GF_RTPChannel *ch)
     719             : {
     720             :         if (!ch) return 0;
     721             :         if (!ch->rtp_first_SN && !ch->rtp_time) return 0;
     722             :         return 1;
     723             : }
     724             : #endif
     725             : 
     726             : GF_EXPORT
     727           4 : u8 gf_rtp_get_low_interleave_id(GF_RTPChannel *ch)
     728             : {
     729           4 :         if (!ch || !ch->net_info.IsInterleaved) return 0;
     730           4 :         return ch->net_info.rtpID;
     731             : }
     732             : 
     733             : GF_EXPORT
     734           4 : u8 gf_rtp_get_hight_interleave_id(GF_RTPChannel *ch)
     735             : {
     736           4 :         if (!ch || !ch->net_info.IsInterleaved) return 0;
     737           4 :         return ch->net_info.rtcpID;
     738             : }
     739             : 
     740             : 
     741             : #define RTP_DEFAULT_FIRSTPORT           7040
     742             : 
     743             : static u16 NextAvailablePort = 0;
     744             : 
     745             : GF_EXPORT
     746          36 : GF_Err gf_rtp_set_ports(GF_RTPChannel *ch, u16 first_port)
     747             : {
     748             :         u16 p;
     749             :         GF_Socket *sock;
     750          36 :         if (!ch) return GF_BAD_PARAM;
     751             : 
     752          36 :         if (!NextAvailablePort) {
     753          35 :                 NextAvailablePort = first_port ? first_port : RTP_DEFAULT_FIRSTPORT;
     754             :         }
     755          36 :         p = NextAvailablePort;
     756          36 :         if (ch->net_info.client_port_first) return GF_OK;
     757             : 
     758          36 :         sock = gf_sk_new(GF_SOCK_TYPE_UDP);
     759          36 :         if (!sock) return GF_IO_ERR;
     760             : 
     761             :         /*should be way enough (more than 100 rtp streams open on the machine)*/
     762           0 :         while (1) {
     763             :                 /*try to bind without reuse. If fails this means the port is used on the machine, don't reuse it*/
     764          36 :                 GF_Err e = gf_sk_bind(sock, NULL, p, NULL, 0, 0);
     765          36 :                 if (e==GF_OK) break;
     766           0 :                 if (e!=GF_IP_CONNECTION_FAILURE) {
     767           0 :                         gf_sk_del(sock);
     768           0 :                         return GF_IP_NETWORK_FAILURE;
     769             :                 }
     770           0 :                 p+=2;
     771             :         }
     772          36 :         gf_sk_del(sock);
     773          36 :         ch->net_info.client_port_first = p;
     774          36 :         ch->net_info.client_port_last = p + 1;
     775          36 :         NextAvailablePort = p + 2;
     776          36 :         return GF_OK;
     777             : }
     778             : 
     779             : 
     780             : GF_EXPORT
     781          19 : GF_Err gf_rtp_setup_payload(GF_RTPChannel *ch, u32 PayloadType, u32 ClockRate)
     782             : {
     783          19 :         if (!ch || !PayloadType || !ClockRate) return GF_BAD_PARAM;
     784          19 :         ch->PayloadType = PayloadType;
     785          19 :         ch->TimeScale = ClockRate;
     786          19 :         return GF_OK;
     787             : }
     788             : 
     789             : GF_EXPORT
     790           6 : const GF_RTSPTransport *gf_rtp_get_transport(GF_RTPChannel *ch)
     791             : {
     792           6 :         if (!ch) return NULL;
     793           6 :         return &ch->net_info;
     794             : }
     795             : 
     796             : #if 0 //unused
     797             : u32 gf_rtp_get_local_ssrc(GF_RTPChannel *ch)
     798             : {
     799             :         if (!ch) return 0;
     800             :         return ch->SSRC;
     801             : }
     802             : #endif
     803             : 
     804             : #if 0
     805             : "#RTP log format:\n"
     806             : "#RTP SenderSSRC RTP_TimeStamp RTP_SeqNum NTP@Recv Deviance Jitter NbLost NbTotPck NbTotBytes\n"
     807             : "#RTCP Sender reports log format:\n"
     808             : "#RTCP-SR SenderSSRC RTP_TimeStamp@NTP NbTotPck NbTotBytes NTP\n"
     809             : "#RTCP Receiver reports log format:\n"
     810             : "#RTCP-RR StreamSSRC Jitter ExtendedSeqNum ExpectDiff LossDiff NTP\n"
     811             : #endif
     812             : 
     813             : GF_EXPORT
     814          52 : Float gf_rtp_get_loss(GF_RTPChannel *ch)
     815             : {
     816          52 :         if (!ch->tot_num_pck_expected) return 0.0f;
     817           0 :         return 100.0f - (100.0f * ch->tot_num_pck_rcv) / ch->tot_num_pck_expected;
     818             : }
     819             : 
     820             : GF_EXPORT
     821          52 : u32 gf_rtp_get_tcp_bytes_sent(GF_RTPChannel *ch)
     822             : {
     823          52 :         return ch->rtcp_bytes_sent;
     824             : }
     825             : 
     826             : GF_EXPORT
     827          30 : void gf_rtp_get_ports(GF_RTPChannel *ch, u16 *rtp_port, u16 *rtcp_port)
     828             : {
     829          30 :         if (ch->net_info.client_port_first) {
     830          29 :                 if (rtp_port) *rtp_port = ch->net_info.client_port_first;
     831          29 :                 if (rtcp_port) *rtcp_port = ch->net_info.client_port_last;
     832             :         } else {
     833           1 :                 if (rtp_port) *rtp_port = ch->net_info.port_first;
     834           1 :                 if (rtcp_port) *rtcp_port = ch->net_info.port_last;
     835             :         }
     836          30 : }
     837             : 
     838             : 
     839             : /*
     840             :         RTP packet reorderer
     841             : */
     842             : 
     843             : #define SN_CHECK_OFFSET         0x0A
     844             : 
     845             : GF_EXPORT
     846          19 : GF_RTPReorder *gf_rtp_reorderer_new(u32 MaxCount, u32 MaxDelay)
     847             : {
     848             :         GF_RTPReorder *tmp;
     849             : 
     850          19 :         if (MaxCount <= 1 || !MaxDelay) return NULL;
     851             : 
     852          19 :         GF_SAFEALLOC(tmp , GF_RTPReorder);
     853          19 :         if (!tmp) return NULL;
     854          19 :         tmp->MaxCount = MaxCount;
     855          19 :         tmp->MaxDelay = MaxDelay;
     856          19 :         return tmp;
     857             : }
     858             : 
     859             : GF_EXPORT
     860          19 : void gf_rtp_reorderer_del(GF_RTPReorder *po)
     861             : {
     862          19 :         gf_rtp_reorderer_reset(po);
     863          19 :         gf_free(po);
     864          19 : }
     865             : 
     866             : GF_EXPORT
     867          48 : void gf_rtp_reorderer_reset(GF_RTPReorder *po)
     868             : {
     869             :         GF_POItem *item;
     870          48 :         if (!po) return;
     871             : 
     872          48 :         item = po->in;
     873          96 :         while (item) {
     874           0 :                 GF_POItem *next = item->next;
     875           0 :                 gf_free(item->pck);
     876           0 :                 gf_free(item);
     877             :                 item = next;
     878             :         }
     879             : 
     880          48 :         po->head_seqnum = 0;
     881          48 :         po->Count = 0;
     882          48 :         po->IsInit = 0;
     883          48 :         po->in = NULL;
     884             : }
     885             : 
     886             : GF_EXPORT
     887         742 : GF_Err gf_rtp_reorderer_add(GF_RTPReorder *po, const void * pck, u32 pck_size, u32 pck_seqnum)
     888             : {
     889             :         GF_POItem *it, *cur;
     890             :         u32 bounds;
     891             : 
     892         742 :         if (!po) return GF_BAD_PARAM;
     893             : 
     894         742 :         it = (GF_POItem *) gf_malloc(sizeof(GF_POItem));
     895         742 :         it->pck_seq_num = pck_seqnum;
     896         742 :         it->next = NULL;
     897         742 :         it->size = pck_size;
     898         742 :         it->pck = gf_malloc(pck_size);
     899             :         memcpy(it->pck, pck, pck_size);
     900             :         /*reset timeout*/
     901         742 :         po->LastTime = 0;
     902             : 
     903             :         //no input, this packet will be the input
     904         742 :         if (!po->in) {
     905             :                 //the seq num was not initialized
     906          19 :                 if (!po->head_seqnum) {
     907          19 :                         po->head_seqnum = pck_seqnum;
     908           0 :                 } else if (!po->IsInit) {
     909             :                         //this is not in our current range for init
     910           0 :                         if (ABSDIFF(po->head_seqnum, pck_seqnum) > SN_CHECK_OFFSET) goto discard;
     911           0 :                         po->IsInit = 1;
     912             :                 }
     913             : 
     914          19 :                 po->in = it;
     915          19 :                 po->Count += 1;
     916          19 :                 return GF_OK;
     917             :         }
     918             : 
     919             :         //this is 16 bitr seq num, as we work with RTP only for now
     920             :         bounds = 0;
     921         723 :         if ( (po->head_seqnum >= 0xf000 ) || (po->head_seqnum <= 0x1000) ) bounds = 0x2000;
     922             : 
     923             :         //first check the head of the list
     924             :         //same seq num, we drop
     925         723 :         if (po->in->pck_seq_num == pck_seqnum) goto discard;
     926             : 
     927         723 :         if ( ( (u16) (pck_seqnum + bounds) <= (u16) (po->in->pck_seq_num + bounds) ) ) {
     928             : 
     929           0 :                 it->next = po->in;
     930           0 :                 po->in = it;
     931           0 :                 po->Count += 1;
     932             : 
     933           0 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: inserting packet %d at head\n", pck_seqnum));
     934             :                 return GF_OK;
     935             :         }
     936             : 
     937             :         //no, insert at the right place
     938             :         cur = po->in;
     939             : 
     940             :         while (1) {
     941             :                 //same seq num, we drop
     942         723 :                 if (cur->pck_seq_num == pck_seqnum) goto discard;
     943             : 
     944             :                 //end of list
     945         723 :                 if (!cur->next) {
     946         723 :                         cur->next = it;
     947         723 :                         po->Count += 1;
     948         723 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: Appending packet %d (last %d)\n", pck_seqnum, cur->pck_seq_num));
     949             :                         return GF_OK;
     950             :                 }
     951             : 
     952             :                 //are we in the bounds ??
     953           0 :                 if ( ( (u16) (cur->pck_seq_num + bounds) < (u16) (pck_seqnum + bounds) )
     954           0 :                         && ( (u16) (pck_seqnum + bounds) < (u16) (cur->next->pck_seq_num + bounds)) ) {
     955             : 
     956             :                         //insert
     957           0 :                         it->next = cur->next;
     958           0 :                         cur->next = it;
     959           0 :                         po->Count += 1;
     960             : 
     961           0 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: Inserting packet %d\n", pck_seqnum));
     962             :                         //done
     963             :                         return GF_OK;
     964             :                 }
     965             :                 cur = cur->next;
     966             :         }
     967             : 
     968             : 
     969           0 : discard:
     970           0 :         gf_free(it->pck);
     971           0 :         gf_free(it);
     972           0 :         GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[rtp] Packet Reorderer: Dropping packet %d\n", pck_seqnum));
     973             :         return GF_OK;
     974             : }
     975             : 
     976             : //retrieve the first available packet. Note that the behavior will be undefined if the first
     977             : //ever received packet if its SeqNum was unknown
     978             : //the BUFFER is yours, you must delete it
     979             : GF_EXPORT
     980         786 : void *gf_rtp_reorderer_get(GF_RTPReorder *po, u32 *pck_size, Bool force_flush)
     981             : {
     982             :         GF_POItem *t;
     983             :         u32 bounds;
     984             :         void *ret;
     985             : 
     986         786 :         if (!po || !pck_size) return NULL;
     987             : 
     988         786 :         *pck_size = 0;
     989             : 
     990             :         //empty queue
     991         786 :         if (!po->in) return NULL;
     992             : 
     993             :         //check we have received the first packet
     994         761 :         if ( po->head_seqnum && po->MaxCount
     995         761 :                 && (po->MaxCount > po->Count)
     996         761 :                 && (po->in->pck_seq_num != po->head_seqnum))
     997             :                 return NULL;
     998             : 
     999             :         //no entry
    1000         761 :         if (!po->in->next) goto check_timeout;
    1001             : 
    1002             :         bounds = 0;
    1003         723 :         if ( (po->head_seqnum >= 0xf000 ) || (po->head_seqnum <= 0x1000) ) bounds = 0x2000;
    1004             : 
    1005             :         //release the output if SN in order or maxCount reached
    1006         723 :         if (( (u16) (po->in->pck_seq_num + bounds + 1) == (u16) (po->in->next->pck_seq_num + bounds))
    1007           0 :                 || (po->MaxCount && (po->Count >= po->MaxCount)) ) {
    1008             : 
    1009             : #ifndef GPAC_DISABLE_LOG
    1010         723 :                 if (po->in->pck_seq_num + 1 != po->in->next->pck_seq_num)
    1011           0 :                         GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[rtp] WARNING Packet Loss: Sending %d out of the queue but next is %d\n", po->in->pck_seq_num, po->in->next->pck_seq_num ));
    1012             : #endif
    1013             :                 goto send_it;
    1014             :         }
    1015             :         //update timing
    1016             :         else {
    1017          38 : check_timeout:
    1018             : 
    1019          38 :                 if (force_flush) goto send_it;
    1020             : 
    1021          19 :                 if (!po->LastTime) {
    1022          19 :                         po->LastTime = gf_sys_clock();
    1023          19 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: starting timeout at %d\n", po->LastTime));
    1024             :                         return NULL;
    1025             :                 }
    1026             :                 //if exceeding the delay send the head
    1027           0 :                 if (gf_sys_clock() - po->LastTime >= po->MaxDelay) {
    1028           0 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: Forcing output after %d ms wait (max allowed %d)\n", gf_sys_clock() - po->LastTime, po->MaxDelay));
    1029             :                         goto send_it;
    1030             :                 }
    1031             :         }
    1032             :         return NULL;
    1033             : 
    1034             : 
    1035         761 : send_it:
    1036         742 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: Fetching %d\n", po->in->pck_seq_num));
    1037         742 :         *pck_size = po->in->size;
    1038         742 :         t = po->in;
    1039         742 :         po->in = po->in->next;
    1040             :         //no other output. reset the head seqnum
    1041         742 :         po->head_seqnum = po->in ? po->in->pck_seq_num : 0;
    1042         742 :         po->Count -= 1;
    1043             :         //release the item
    1044         742 :         ret = t->pck;
    1045         742 :         gf_free(t);
    1046         742 :         return ret;
    1047             : }
    1048             : 
    1049           2 : GF_Err gf_rtp_set_interleave_callbacks(GF_RTPChannel *ch, gf_rtp_tcp_callback RTP_TCPCallback, void *cbk1, void *cbk2)
    1050             : {
    1051           2 :         if (!ch) return GF_BAD_PARAM;
    1052           2 :         ch->send_interleave = RTP_TCPCallback;
    1053           2 :         ch->interleave_cbk1 = cbk1;
    1054           2 :         ch->interleave_cbk2 = cbk2;
    1055           2 :         return GF_OK;
    1056             : }
    1057             : 
    1058             : 
    1059             : #endif /*GPAC_DISABLE_STREAMING*/
    1060             : 

Generated by: LCOV version 1.13