Coverage Report

Created: 2026-06-08 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/ietf/rtp_streamer.c
Line
Count
Source
1
/*
2
 *      GPAC - Multimedia Framework C SDK
3
 *
4
 *      Authors: Jean Le Feuvre
5
 *      Copyright (c) Telecom ParisTech 2000-2024
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
27
#include <gpac/rtp_streamer.h>
28
#include <gpac/constants.h>
29
#include <gpac/base_coding.h>
30
#ifndef GPAC_DISABLE_AV_PARSERS
31
#include <gpac/avparse.h>
32
#endif
33
#include <gpac/internal/ietf_dev.h>
34
35
#if !defined(GPAC_DISABLE_STREAMING)
36
37
/*for ISOBMFF subtypes*/
38
#include <gpac/isomedia.h>
39
40
0
#define RTCP_BUF_SIZE 10000
41
struct __rtp_streamer
42
{
43
  GP_RTPPacketizer *packetizer;
44
  GF_RTPChannel *channel;
45
46
  /* The current packet being formed */
47
  char *buffer;
48
  u32 payload_len, buffer_alloc;
49
50
  u32 in_timescale;
51
  char rtcp_buf[RTCP_BUF_SIZE];
52
53
  const char *netcap_id;
54
  GF_Err last_err;
55
};
56
57
58
/*callbacks from packetizer to channel*/
59
60
static void rtp_stream_on_new_packet(void *cbk, GF_RTPHeader *header)
61
0
{
62
0
}
63
64
static void rtp_stream_on_packet_done(void *cbk, GF_RTPHeader *header)
65
0
{
66
0
  GF_RTPStreamer *rtp = (GF_RTPStreamer*)cbk;
67
0
  GF_Err e = gf_rtp_send_packet(rtp->channel, header, rtp->buffer+12, rtp->payload_len, GF_TRUE);
68
69
0
#ifndef GPAC_DISABLE_LOG
70
0
  if (e) {
71
0
    rtp->last_err = e;
72
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP] Error %s sending RTP packet SN %u - TS %u\n", gf_error_to_string(e), header->SequenceNumber, header->TimeStamp));
73
0
  } else {
74
0
    GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("RTP SN %u - TS %u - M %u - Size %u\n", header->SequenceNumber, header->TimeStamp, header->Marker, rtp->payload_len + 12));
75
0
  }
76
#else
77
  if (e) {
78
    fprintf(stderr, "Error %s sending RTP packet SN %u - TS %u\n", gf_error_to_string(e), header->SequenceNumber, header->TimeStamp);
79
  }
80
#endif
81
0
  rtp->payload_len = 0;
82
0
}
83
84
static void rtp_stream_on_data(void *cbk, u8 *data, u32 data_size, Bool is_head)
85
0
{
86
0
  GF_RTPStreamer *rtp = (GF_RTPStreamer*)cbk;
87
0
  if (!data ||!data_size) return;
88
89
0
  if (rtp->payload_len+data_size+12 > rtp->buffer_alloc) {
90
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP] Packet size %d bigger than MTU size %d - discarding\n", rtp->payload_len+data_size+12, rtp->buffer_alloc));
91
0
    rtp->payload_len += data_size;
92
0
    return;
93
0
  }
94
0
  if (!is_head) {
95
0
    memcpy(rtp->buffer + rtp->payload_len + 12, data, data_size);
96
0
  } else {
97
0
    memmove(rtp->buffer + data_size + 12, rtp->buffer + 12, rtp->payload_len);
98
0
    memcpy(rtp->buffer + 12, data, data_size);
99
0
  }
100
0
  rtp->payload_len += data_size;
101
0
}
102
103
104
GF_Err gf_rtp_streamer_init_rtsp(GF_RTPStreamer *rtp, u32 path_mtu, GF_RTSPTransport *tr, const char *ifce_addr)
105
0
{
106
0
  GF_Err res;
107
108
0
  if (!rtp->channel) {
109
0
    rtp->channel = gf_rtp_new_ex(rtp->netcap_id);
110
0
    if (!rtp->channel) return GF_OUT_OF_MEM;
111
0
    rtp->channel->TimeScale = rtp->packetizer->sl_config.timestampResolution;
112
0
  }
113
0
  res = gf_rtp_setup_transport(rtp->channel, tr, tr->destination);
114
0
  if (res !=0) {
115
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("Cannot setup RTP transport info: %s\n", gf_error_to_string(res) ));
116
0
    return res;
117
0
  }
118
119
0
  res = gf_rtp_initialize(rtp->channel, 0, GF_TRUE, path_mtu, 0, 0, (char *)ifce_addr);
120
0
  if (res !=0) {
121
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("Cannot initialize RTP sockets: %s\n", gf_error_to_string(res) ));
122
0
    return res;
123
0
  }
124
0
  return GF_OK;
125
0
}
126
static GF_Err rtp_stream_init_channel(GF_RTPStreamer *rtp, u32 path_mtu, const char * dest, int port, int ttl, const char *ifce_addr, const char *netcap_id)
127
0
{
128
0
  GF_RTSPTransport tr;
129
0
  GF_Err res;
130
131
0
  rtp->channel = gf_rtp_new_ex(netcap_id);
132
0
  if (!rtp->channel) return GF_OUT_OF_MEM;
133
0
  rtp->channel->TimeScale = rtp->packetizer->sl_config.timestampResolution;
134
135
  //gf_rtp_set_ports(rtp->channel, 0);
136
0
  memset(&tr, 0, sizeof(GF_RTSPTransport));
137
138
0
  tr.IsUnicast = gf_sk_is_multicast_address(dest) ? GF_FALSE : GF_TRUE;
139
0
  tr.Profile="RTP/AVP";
140
0
  tr.destination = (char *)dest;
141
0
  tr.source = "0.0.0.0";
142
0
  tr.IsRecord = GF_FALSE;
143
0
  tr.Append = GF_FALSE;
144
0
  tr.SSRC = rand();
145
0
  tr.TTL = ttl;
146
147
0
  tr.port_first = port;
148
0
  tr.port_last = port+1;
149
0
  if (tr.IsUnicast) {
150
0
    tr.client_port_first = port;
151
0
    tr.client_port_last  = port+1;
152
0
  } else {
153
0
    tr.source = (char *)dest;
154
0
  }
155
156
0
  res = gf_rtp_setup_transport(rtp->channel, &tr, dest);
157
0
  if (res !=0) {
158
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("Cannot setup RTP transport info: %s\n", gf_error_to_string(res) ));
159
0
    return res;
160
0
  }
161
162
0
  res = gf_rtp_initialize(rtp->channel, 0, GF_TRUE, path_mtu, 0, 0, (char *)ifce_addr);
163
0
  if (res !=0) {
164
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("Cannot initialize RTP sockets: %s\n", gf_error_to_string(res) ));
165
0
    return res;
166
0
  }
167
0
  return GF_OK;
168
0
}
169
170
GF_EXPORT
171
GF_RTPStreamer *gf_rtp_streamer_new_ex(const GF_RTPStreamerConfig *cfg, Bool for_rtsp)
172
0
{
173
0
  GF_SLConfig slc;
174
0
  GF_RTPStreamer *stream;
175
0
  u32 rtp_type, default_rtp_rate;
176
0
  u8 OfficialPayloadType;
177
0
  u32 required_rate, force_dts_delta, PL_ID;
178
0
  char *mpeg4mode;
179
0
  Bool has_mpeg4_mapping;
180
0
  GF_Err e;
181
182
0
  u32 timeScale = cfg->timeScale ? cfg->timeScale : 1000;
183
0
  u32 flags = cfg->flags;
184
0
  u32 streamType = cfg->streamType;
185
0
  u32 codecid = cfg->codecid;
186
0
  u32 PayloadType = cfg->PayloadType;
187
0
  u32 maxDTSDelta = cfg->maxDTSDelta;
188
0
  u32 max_ptime = cfg->max_ptime;
189
190
0
  GF_SAFEALLOC(stream, GF_RTPStreamer);
191
0
  if (!stream) return NULL;
192
193
194
  /*by default NO PL signaled*/
195
0
  PL_ID = 0;
196
0
  OfficialPayloadType = 0;
197
0
  force_dts_delta = 0;
198
0
  mpeg4mode = NULL;
199
0
  required_rate = 0;
200
0
  has_mpeg4_mapping = GF_TRUE;
201
0
  rtp_type = 0;
202
203
  /*for max compatibility with QT*/
204
0
  default_rtp_rate = 90000;
205
206
  /*timed-text is a bit special, we support multiple stream descriptions & co*/
207
0
  switch (cfg->streamType) {
208
0
  case GF_STREAM_AUDIO:
209
0
    required_rate = cfg->sample_rate;
210
0
    break;
211
0
  case GF_STREAM_VISUAL:
212
0
    rtp_type = GF_RTP_PAYT_MPEG4;
213
0
    required_rate = default_rtp_rate;
214
0
    if (cfg->is_crypted) {
215
      /*that's another pain with ISMACryp, even if no B-frames the DTS is signaled...*/
216
0
      if (cfg->codecid==GF_CODECID_MPEG4_PART2) force_dts_delta = 22;
217
0
      flags |= GP_RTP_PCK_SIGNAL_RAP | GP_RTP_PCK_SIGNAL_TS;
218
0
    }
219
0
    break;
220
0
  case GF_STREAM_SCENE:
221
0
  case GF_STREAM_OD:
222
0
    if (cfg->codecid == GF_CODECID_DIMS) {
223
#if GPAC_ENABLE_3GPP_DIMS_RTP
224
      rtp_type = GF_RTP_PAYT_3GPP_DIMS;
225
      has_mpeg4_mapping = GF_FALSE;
226
#else
227
0
      gf_rtp_streamer_del(stream);
228
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP Packetizer] 3GPP DIMS over RTP disabled in build\n", cfg->streamType));
229
0
      return NULL;
230
0
#endif
231
0
    } else {
232
0
      rtp_type = GF_RTP_PAYT_MPEG4;
233
0
    }
234
0
    break;
235
0
  }
236
237
0
  switch (cfg->codecid) {
238
  /*AAC*/
239
0
  case GF_CODECID_AAC_MPEG4:
240
0
  case GF_CODECID_AAC_MPEG2_MP:
241
0
  case GF_CODECID_AAC_MPEG2_LCP:
242
0
  case GF_CODECID_AAC_MPEG2_SSRP:
243
0
    PL_ID = 0x01;
244
0
    mpeg4mode = "AAC";
245
0
    rtp_type = GF_RTP_PAYT_MPEG4;
246
0
    required_rate = cfg->sample_rate;
247
248
0
#ifndef GPAC_DISABLE_AV_PARSERS
249
0
    if (cfg->dsi) {
250
0
      GF_M4ADecSpecInfo a_cfg;
251
0
      gf_m4a_get_config((u8 *)cfg->dsi, cfg->dsi_len, &a_cfg);
252
      //nb_ch = a_cfg.nb_chan;
253
      //sample_rate = a_cfg.base_sr;
254
0
      PL_ID = a_cfg.audioPL;
255
0
      switch (a_cfg.base_object_type) {
256
0
      case GF_M4A_AAC_MAIN:
257
0
      case GF_M4A_AAC_LC:
258
0
        if (flags & GP_RTP_PCK_USE_LATM_AAC) {
259
0
          rtp_type = GF_RTP_PAYT_LATM;
260
0
          break;
261
0
        }
262
0
      case GF_M4A_AAC_SBR:
263
0
      case GF_M4A_AAC_PS:
264
0
      case GF_M4A_AAC_LTP:
265
0
      case GF_M4A_AAC_SCALABLE:
266
0
      case GF_M4A_ER_AAC_LC:
267
0
      case GF_M4A_ER_AAC_LTP:
268
0
      case GF_M4A_ER_AAC_SCALABLE:
269
0
        mpeg4mode = "AAC";
270
0
        break;
271
0
      case GF_M4A_CELP:
272
0
      case GF_M4A_ER_CELP:
273
0
        mpeg4mode = "CELP";
274
0
        break;
275
0
      }
276
0
    }
277
0
#endif
278
0
    break;
279
280
  /*MPEG1/2 audio*/
281
0
  case GF_CODECID_MPEG2_PART3:
282
0
  case GF_CODECID_MPEG_AUDIO:
283
0
  case GF_CODECID_MPEG_AUDIO_L1:
284
0
    if (!cfg->is_crypted) {
285
0
      rtp_type = GF_RTP_PAYT_MPEG12_AUDIO;
286
      /*use official RTP/AVP payload type*/
287
0
      OfficialPayloadType = 14;
288
0
      required_rate = 90000;
289
0
    }
290
    /*encrypted MP3 must be sent through MPEG-4 generic to signal all ISMACryp stuff*/
291
0
    else {
292
0
      rtp_type = GF_RTP_PAYT_MPEG4;
293
0
    }
294
0
    break;
295
296
  /*ISO/IEC 14496-2*/
297
0
  case GF_CODECID_MPEG4_PART2:
298
0
    PL_ID = 1;
299
0
#ifndef GPAC_DISABLE_AV_PARSERS
300
0
    if (cfg->dsi) {
301
0
      GF_M4VDecSpecInfo vhdr;
302
0
      gf_m4v_get_config((u8 *)cfg->dsi, cfg->dsi_len, &vhdr);
303
0
      PL_ID = vhdr.VideoPL;
304
0
    }
305
0
#endif
306
0
    break;
307
308
  /*MPEG1/2 video*/
309
0
  case GF_CODECID_MPEG1:
310
0
  case GF_CODECID_MPEG2_SIMPLE:
311
0
  case GF_CODECID_MPEG2_MAIN:
312
0
  case GF_CODECID_MPEG2_SNR:
313
0
  case GF_CODECID_MPEG2_SPATIAL:
314
0
  case GF_CODECID_MPEG2_HIGH:
315
0
  case GF_CODECID_MPEG2_422:
316
0
    if (!cfg->is_crypted) {
317
0
      rtp_type = GF_RTP_PAYT_MPEG12_VIDEO;
318
0
      OfficialPayloadType = 32;
319
0
    }
320
0
    break;
321
  /*AVC/H.264*/
322
0
  case GF_CODECID_AVC:
323
0
    required_rate = 90000;  /* "90 kHz clock rate MUST be used"*/
324
0
    rtp_type = GF_RTP_PAYT_H264_AVC;
325
0
    PL_ID = 0x0F;
326
0
    break;
327
  /*H264-SVC*/
328
0
  case GF_CODECID_SVC:
329
0
  case GF_CODECID_MVC:
330
0
    required_rate = 90000;  /* "90 kHz clock rate MUST be used"*/
331
0
    rtp_type = GF_RTP_PAYT_H264_SVC;
332
0
    PL_ID = 0x0F;
333
0
    break;
334
335
  /*HEVC*/
336
0
  case GF_CODECID_HEVC:
337
0
    required_rate = 90000;  /* "90 kHz clock rate MUST be used"*/
338
0
    rtp_type = GF_RTP_PAYT_HEVC;
339
0
    PL_ID = 0x0F;
340
0
    break;
341
  /*LHVC*/
342
0
  case GF_CODECID_LHVC:
343
0
    required_rate = 90000;  /* "90 kHz clock rate MUST be used"*/
344
0
    rtp_type = GF_RTP_PAYT_LHVC;
345
0
    PL_ID = 0x0F;
346
0
    break;
347
  /*VVC*/
348
0
  case GF_CODECID_VVC:
349
0
    required_rate = 90000;  /* "90 kHz clock rate MUST be used"*/
350
0
    rtp_type = GF_RTP_PAYT_VVC;
351
0
    PL_ID = 0x0F;
352
0
    break;
353
0
  case GF_CODECID_H263:
354
0
    rtp_type = GF_RTP_PAYT_H263;
355
0
    required_rate = 90000;
356
0
    streamType = GF_STREAM_VISUAL;
357
0
    OfficialPayloadType = 34;
358
    /*not 100% compliant (short header is missing) but should still work*/
359
0
    codecid = GF_CODECID_MPEG4_PART2;
360
0
    PL_ID = 0x01;
361
0
    break;
362
0
  case GF_CODECID_AMR:
363
0
    required_rate = 8000;
364
0
    rtp_type = GF_RTP_PAYT_AMR;
365
0
    streamType = GF_STREAM_AUDIO;
366
0
    has_mpeg4_mapping = GF_FALSE;
367
0
    break;
368
0
  case GF_CODECID_AMR_WB:
369
0
    required_rate = 16000;
370
0
    rtp_type = GF_RTP_PAYT_AMR_WB;
371
0
    streamType = GF_STREAM_AUDIO;
372
0
    has_mpeg4_mapping = GF_FALSE;
373
0
    break;
374
0
  case GF_CODECID_AC3:
375
0
    rtp_type = GF_RTP_PAYT_AC3;
376
0
    streamType = GF_STREAM_AUDIO;
377
0
    has_mpeg4_mapping = GF_TRUE;
378
0
    break;
379
0
  case GF_CODECID_EAC3:
380
0
    rtp_type = GF_RTP_PAYT_EAC3;
381
0
    streamType = GF_STREAM_AUDIO;
382
0
    has_mpeg4_mapping = GF_FALSE;
383
0
    break;
384
385
0
  case GF_CODECID_QCELP:
386
0
    required_rate = 8000;
387
0
    rtp_type = GF_RTP_PAYT_QCELP;
388
0
    streamType = GF_STREAM_AUDIO;
389
0
    codecid = GF_CODECID_QCELP;
390
0
    OfficialPayloadType = 12;
391
//      nb_ch = 1;
392
0
    break;
393
0
  case GF_CODECID_EVRC:
394
0
  case GF_CODECID_SMV:
395
0
    required_rate = 8000;
396
0
    rtp_type = GF_RTP_PAYT_EVRC_SMV;
397
0
    streamType = GF_STREAM_AUDIO;
398
0
    codecid = (codecid==GF_ISOM_SUBTYPE_3GP_EVRC) ? GF_CODECID_EVRC : GF_CODECID_SMV;
399
//      nb_ch = 1;
400
0
    break;
401
0
  case GF_CODECID_TX3G:
402
0
    rtp_type = GF_RTP_PAYT_3GPP_TEXT;
403
    /*fixme - this works cos there's only one PL for text in mpeg4 at the current time*/
404
0
    PL_ID = 0x10;
405
0
    break;
406
0
  case GF_CODECID_TEXT_MPEG4:
407
0
    rtp_type = GF_RTP_PAYT_3GPP_TEXT;
408
    /*fixme - this works cos there's only one PL for text in mpeg4 at the current time*/
409
0
    PL_ID = 0x10;
410
0
    break;
411
0
  case GF_CODECID_FAKE_MP2T:
412
0
    rtp_type = GF_RTP_PAYT_MP2T;
413
0
    PayloadType = OfficialPayloadType = GF_RTP_PAYT_MP2T;
414
0
    required_rate = 90000;
415
0
    break;
416
0
  case GF_CODECID_OPUS:
417
0
    rtp_type = GF_RTP_PAYT_OPUS;
418
0
    streamType = GF_STREAM_AUDIO;
419
0
    has_mpeg4_mapping = GF_FALSE;
420
0
    break;
421
422
0
  default:
423
0
    if (!rtp_type) {
424
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP Packetizer] Unsupported stream type %x\n", streamType));
425
0
      gf_rtp_streamer_del(stream);
426
0
      return NULL;
427
0
    }
428
0
    break;
429
0
  }
430
431
0
  if (flags & GP_RTP_PCK_FORCE_STATIC_ID) {
432
0
    if (!OfficialPayloadType) {
433
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP Packetizer] Codec type %s requires SDP output\n",  gf_codecid_name(codecid) ));
434
0
      gf_rtp_streamer_del(stream);
435
0
      return NULL;
436
0
    }
437
0
    PayloadType = OfficialPayloadType;
438
0
  }
439
  /*override hinter type if requested and possible*/
440
0
  else if (has_mpeg4_mapping && (flags & GP_RTP_PCK_FORCE_MPEG4)) {
441
0
    rtp_type = GF_RTP_PAYT_MPEG4;
442
0
  }
443
  /*use static payload ID if enabled*/
444
0
  else if (OfficialPayloadType && (flags & GP_RTP_PCK_USE_STATIC_ID) ) {
445
0
    PayloadType = OfficialPayloadType;
446
0
  }
447
448
  /*systems carousel: we need at least IDX and RAP signaling*/
449
0
  if (flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) {
450
0
    flags |= GP_RTP_PCK_SIGNAL_RAP;
451
0
  }
452
453
  /*update flags in MultiSL*/
454
0
  if (flags & GP_RTP_PCK_USE_MULTI) {
455
0
    if (cfg->MinSize != cfg->MaxSize) flags |= GP_RTP_PCK_SIGNAL_SIZE;
456
0
    if (!cfg->const_dur) flags |= GP_RTP_PCK_SIGNAL_TS;
457
0
  }
458
459
  /*default SL for RTP */
460
0
  memset(&slc, 0, sizeof(GF_SLConfig));
461
0
  slc.tag = GF_ODF_SLC_TAG;
462
0
  slc.useTimestampsFlag = 1;
463
0
  slc.timestampLength = 32;
464
0
  slc.timestampResolution = timeScale;
465
466
  /*override clockrate if set*/
467
0
  if (required_rate) {
468
0
    Double sc = required_rate;
469
0
    sc /= slc.timestampResolution;
470
0
    maxDTSDelta = (u32) (maxDTSDelta*sc);
471
0
    slc.timestampResolution = required_rate;
472
0
  }
473
  /*switch to RTP TS*/
474
0
  max_ptime = (u32) (max_ptime * slc.timestampResolution / 1000);
475
476
0
  slc.AUSeqNumLength = cfg->au_sn_len;
477
0
  slc.CUDuration = cfg->const_dur;
478
479
0
  if (flags & GP_RTP_PCK_SIGNAL_RAP) {
480
0
    slc.useRandomAccessPointFlag = 1;
481
0
  } else {
482
0
    slc.useRandomAccessPointFlag = 0;
483
0
    slc.hasRandomAccessUnitsOnlyFlag = 1;
484
0
  }
485
486
0
  stream->packetizer = gf_rtp_builder_new(rtp_type, &slc, flags,
487
0
                                          stream,
488
0
                                          rtp_stream_on_new_packet, rtp_stream_on_packet_done,
489
0
                                          NULL, rtp_stream_on_data);
490
491
0
  if (!stream->packetizer) {
492
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP Packetizer] Failed to create packetizer\n"));
493
0
    gf_rtp_streamer_del(stream);
494
0
    return NULL;
495
0
  }
496
497
0
  gf_rtp_builder_init(stream->packetizer, (u8) PayloadType, cfg->MTU, max_ptime,
498
0
                      streamType, codecid, PL_ID, cfg->MinSize, cfg->MaxSize, cfg->avgTS, maxDTSDelta, cfg->IV_length, cfg->KI_length, mpeg4mode);
499
500
501
0
  if (force_dts_delta) stream->packetizer->slMap.DTSDeltaLength = force_dts_delta;
502
503
0
  if (!for_rtsp) {
504
0
    e = rtp_stream_init_channel(stream, cfg->MTU + 12, cfg->ip_dest, cfg->port, cfg->TTL, cfg->ifce_addr, cfg->netcap_id);
505
0
    if (e) {
506
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP Packetizer] Failed to create RTP channel - error %s\n", gf_error_to_string(e) ));
507
0
      gf_rtp_streamer_del(stream);
508
0
      return NULL;
509
0
    }
510
0
  }
511
512
0
  stream->in_timescale = timeScale;
513
0
  stream->netcap_id = cfg->netcap_id;
514
515
0
  stream->buffer_alloc = cfg->MTU+12;
516
0
  stream->buffer = (char*)gf_malloc(sizeof(char) * stream->buffer_alloc);
517
518
0
  return stream;
519
0
}
520
521
GF_EXPORT
522
GF_RTPStreamer *gf_rtp_streamer_new(u32 streamType, u32 codecid, u32 timeScale,
523
        const char *ip_dest, u16 port, u32 MTU, u8 TTL, const char *ifce_addr,
524
        u32 flags, const u8 *dsi, u32 dsi_len,
525
        u32 PayloadType, u32 sample_rate, u32 nb_ch,
526
        Bool is_crypted, u32 IV_length, u32 KI_length,
527
        u32 MinSize, u32 MaxSize, u32 avgTS, u32 maxDTSDelta, u32 const_dur, u32 bandwidth, u32 max_ptime,
528
        u32 au_sn_len, Bool for_rtsp)
529
0
{
530
0
  GF_RTPStreamerConfig cfg;
531
0
  memset(&cfg, 0, sizeof(GF_RTPStreamerConfig));
532
0
#define RTCFG_SET(_t) cfg._t = _t
533
534
0
  RTCFG_SET(streamType);
535
0
  RTCFG_SET(codecid);
536
0
  RTCFG_SET(timeScale);
537
0
  RTCFG_SET(ip_dest);
538
0
  RTCFG_SET(port);
539
0
  RTCFG_SET(MTU);
540
0
  RTCFG_SET(TTL);
541
0
  RTCFG_SET(ifce_addr);
542
0
  RTCFG_SET(flags);
543
0
  RTCFG_SET(dsi);
544
0
  RTCFG_SET(dsi_len);
545
0
  RTCFG_SET(PayloadType);
546
0
  RTCFG_SET(sample_rate);
547
0
  RTCFG_SET(nb_ch);
548
0
  RTCFG_SET(is_crypted);
549
0
  RTCFG_SET(IV_length);
550
0
  RTCFG_SET(KI_length);
551
0
  RTCFG_SET(MinSize);
552
0
  RTCFG_SET(MaxSize);
553
0
  RTCFG_SET(avgTS);
554
0
  RTCFG_SET(maxDTSDelta);
555
0
  RTCFG_SET(const_dur);
556
0
  RTCFG_SET(bandwidth);
557
0
  RTCFG_SET(max_ptime);
558
0
  RTCFG_SET(au_sn_len);
559
0
#undef RTCFG_SET
560
561
0
  return gf_rtp_streamer_new_ex(&cfg, for_rtsp);
562
0
}
563
564
565
GF_EXPORT
566
void gf_rtp_streamer_del(GF_RTPStreamer *streamer)
567
0
{
568
0
  if (streamer) {
569
0
    if (streamer->channel) gf_rtp_del(streamer->channel);
570
0
    if (streamer->packetizer) gf_rtp_builder_del(streamer->packetizer);
571
0
    if (streamer->buffer) gf_free(streamer->buffer);
572
0
    gf_free(streamer);
573
0
  }
574
0
}
575
576
#if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_STREAMING)
577
578
void gf_media_format_ttxt_sdp(GP_RTPPacketizer *builder, char *payload_name, char **out_sdp_line, u32 w, u32 h, s32 tx, s32 ty, s16 l, u32 max_w, u32 max_h, char *tx3g_base64)
579
0
{
580
0
  char tmp_buf[101];
581
0
  if (!out_sdp_line) return;
582
0
  if (*out_sdp_line)
583
0
    (*out_sdp_line)[0] = 0;
584
585
0
  tmp_buf[100] = 0;
586
0
  snprintf(tmp_buf, 100, "a=fmtp:%d sver=60; ", builder->PayloadType);
587
0
  gf_dynstrcat(out_sdp_line, tmp_buf, NULL);
588
589
0
  snprintf(tmp_buf, 100, "width=%d; height=%d; tx=%d; ty=%d; layer=%d; ", w, h, tx, ty, l);
590
0
  gf_dynstrcat(out_sdp_line, tmp_buf, NULL);
591
592
0
  snprintf(tmp_buf, 100, "max-w=%d; max-h=%d", max_w, max_h);
593
0
  gf_dynstrcat(out_sdp_line, tmp_buf, NULL);
594
595
0
  if (tx3g_base64) {
596
0
    gf_dynstrcat(out_sdp_line, "; tx3g=", NULL);
597
0
    gf_dynstrcat(out_sdp_line, tx3g_base64, NULL);
598
0
  }
599
0
}
600
601
#endif /*!defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_STREAMING)*/
602
603
604
GF_EXPORT
605
GF_Err gf_rtp_streamer_append_sdp_extended(GF_RTPStreamer *rtp, u16 ESID, const u8 *dsi, u32 dsi_len, const u8 *dsi_enh, u32 dsi_enh_len, char *KMS_URI, u32 width, u32 height, u32 tw, u32 th, s32 tx, s32 ty, s16 tl, u32 nb_channels, Bool for_rtsp, char **out_sdp_buffer)
606
0
{
607
0
  u16 port=0;
608
0
  char mediaName[30], payloadName[30];
609
0
  char tmp_buf[101];
610
611
0
  tmp_buf[100]=0;
612
0
  if (!out_sdp_buffer) return GF_BAD_PARAM;
613
614
0
  gf_rtp_builder_get_payload_name(rtp->packetizer, payloadName, mediaName);
615
0
  if (!for_rtsp) {
616
    //this can happen when forwarding a multicast SDP from RTSP, where only a subset of streams have been setup
617
0
    if (!rtp->channel) return GF_OK;
618
0
    gf_rtp_get_ports(rtp->channel, &port, NULL);
619
0
  }
620
621
0
  snprintf(tmp_buf, 100, "m=%s %d RTP/%s %u\n", mediaName, for_rtsp ? 0 : port, rtp->packetizer->slMap.IV_length ? "SAVP" : "AVP", rtp->packetizer->PayloadType);
622
0
  gf_dynstrcat(out_sdp_buffer, tmp_buf, NULL);
623
0
  if (nb_channels > 1)
624
0
    snprintf(tmp_buf, 100, "a=rtpmap:%u %s/%u/%u\n", rtp->packetizer->PayloadType, payloadName, rtp->packetizer->sl_config.timestampResolution, nb_channels);
625
0
  else
626
0
    snprintf(tmp_buf, 100, "a=rtpmap:%u %s/%u\n", rtp->packetizer->PayloadType, payloadName, rtp->packetizer->sl_config.timestampResolution);
627
0
  gf_dynstrcat(out_sdp_buffer, tmp_buf, NULL);
628
629
0
  if (ESID
630
#if GPAC_ENABLE_3GPP_DIMS_RTP
631
    && (rtp->packetizer->rtp_payt != GF_RTP_PAYT_3GPP_DIMS)
632
#endif
633
0
    && (rtp->packetizer->rtp_payt != GF_RTP_PAYT_OPUS)
634
0
   ) {
635
0
    snprintf(tmp_buf, 100, "a=mpeg4-esid:%d\n", ESID);
636
0
    gf_dynstrcat(out_sdp_buffer, tmp_buf, NULL);
637
0
  }
638
639
0
  if (width && height) {
640
0
    if (rtp->packetizer->rtp_payt == GF_RTP_PAYT_H263) {
641
0
      snprintf(tmp_buf, 100, "a=cliprect:0,0,%d,%d\n", height, width);
642
0
      gf_dynstrcat(out_sdp_buffer, tmp_buf, NULL);
643
0
    }
644
    /*extensions for some mobile phones*/
645
0
    snprintf(tmp_buf, 100, "a=framesize:%d %d-%d\n", rtp->packetizer->PayloadType, width, height);
646
0
    gf_dynstrcat(out_sdp_buffer, tmp_buf, NULL);
647
0
  }
648
649
  /*AMR*/
650
0
  if ((rtp->packetizer->rtp_payt == GF_RTP_PAYT_AMR) || (rtp->packetizer->rtp_payt == GF_RTP_PAYT_AMR_WB)) {
651
0
    snprintf(tmp_buf, 100, "a=fmtp:%d octet-align=1\n", rtp->packetizer->PayloadType);
652
0
    gf_dynstrcat(out_sdp_buffer, tmp_buf, NULL);
653
0
  }
654
0
#if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_STREAMING)
655
  /*Text*/
656
0
  else if (rtp->packetizer->rtp_payt == GF_RTP_PAYT_3GPP_TEXT) {
657
0
    char *sdp = NULL;
658
0
    gf_media_format_ttxt_sdp(rtp->packetizer, payloadName, &sdp, tw, th, tx, ty, tl, width, height, (u8 *)dsi_enh);
659
0
    gf_dynstrcat(out_sdp_buffer, sdp, NULL);
660
0
    gf_dynstrcat(out_sdp_buffer, "\n", NULL);
661
0
    if (sdp) gf_free(sdp);
662
0
  }
663
0
#endif
664
  /*EVRC/SMV in non header-free mode*/
665
0
  else if ((rtp->packetizer->rtp_payt == GF_RTP_PAYT_EVRC_SMV) && (rtp->packetizer->auh_size>1)) {
666
0
    snprintf(tmp_buf, 100, "a=fmtp:%d maxptime=%d\n", rtp->packetizer->PayloadType, rtp->packetizer->auh_size*20);
667
0
    gf_dynstrcat(out_sdp_buffer, tmp_buf, NULL);
668
0
  }
669
  /*H264/AVC*/
670
0
  else if ((rtp->packetizer->rtp_payt == GF_RTP_PAYT_H264_AVC) || (rtp->packetizer->rtp_payt == GF_RTP_PAYT_H264_SVC)) {
671
0
    GF_AVCConfig *avcc = dsi ? gf_odf_avc_cfg_read((u8*)dsi, dsi_len) : NULL;
672
673
0
    if (avcc) {
674
0
      snprintf(tmp_buf, 100, "a=fmtp:%d profile-level-id=%02X%02X%02X; packetization-mode=1", rtp->packetizer->PayloadType, avcc->AVCProfileIndication, avcc->profile_compatibility, avcc->AVCLevelIndication);
675
0
      gf_dynstrcat(out_sdp_buffer, tmp_buf, NULL);
676
677
0
      if (gf_list_count(avcc->pictureParameterSets) || gf_list_count(avcc->sequenceParameterSets)) {
678
0
        u32 i, count, b64s;
679
0
        char b64[200];
680
0
        gf_dynstrcat(out_sdp_buffer, "; sprop-parameter-sets=", NULL);
681
682
0
        count = gf_list_count(avcc->sequenceParameterSets);
683
0
        for (i=0; i<count; i++) {
684
0
          GF_NALUFFParam *sl = (GF_NALUFFParam *)gf_list_get(avcc->sequenceParameterSets, i);
685
0
          b64s = gf_base64_encode(sl->data, sl->size, b64, 200);
686
0
          b64[b64s]=0;
687
0
          gf_dynstrcat(out_sdp_buffer, b64, NULL);
688
0
          if (i+1<count) gf_dynstrcat(out_sdp_buffer, ",", NULL);
689
0
        }
690
0
        if (i) gf_dynstrcat(out_sdp_buffer, ",", NULL);
691
0
        count = gf_list_count(avcc->pictureParameterSets);
692
0
        for (i=0; i<count; i++) {
693
0
          GF_NALUFFParam *sl = (GF_NALUFFParam *)gf_list_get(avcc->pictureParameterSets, i);
694
0
          b64s = gf_base64_encode(sl->data, sl->size, b64, 200);
695
0
          b64[b64s]=0;
696
0
          gf_dynstrcat(out_sdp_buffer, b64, NULL);
697
0
          if (i+1<count) gf_dynstrcat(out_sdp_buffer, ",", NULL);
698
0
        }
699
0
      }
700
0
      gf_odf_avc_cfg_del(avcc);
701
0
      gf_dynstrcat(out_sdp_buffer, "\n", NULL);
702
0
    }
703
0
  }
704
0
  else if ((rtp->packetizer->rtp_payt == GF_RTP_PAYT_HEVC)
705
0
    || (rtp->packetizer->rtp_payt == GF_RTP_PAYT_LHVC)
706
0
    || (rtp->packetizer->rtp_payt == GF_RTP_PAYT_VVC)
707
0
  ) {
708
0
    GF_VVCConfig *vvcc = NULL;
709
0
    GF_HEVCConfig *hvcc = NULL;
710
0
    GF_List *param_array = NULL;
711
0
    u8 sps_nut=0, pps_nut=0, vps_nut=0;
712
0
    if (rtp->packetizer->rtp_payt == GF_RTP_PAYT_VVC) {
713
0
      vvcc = dsi ? gf_odf_vvc_cfg_read((u8*)dsi, dsi_len) : NULL;
714
0
      param_array = vvcc ? vvcc->param_array : NULL;
715
0
      sps_nut = GF_VVC_NALU_SEQ_PARAM;
716
0
      pps_nut = GF_VVC_NALU_PIC_PARAM;
717
0
      vps_nut = GF_VVC_NALU_VID_PARAM;
718
0
    } else {
719
0
      if (dsi) {
720
0
        hvcc = gf_odf_hevc_cfg_read((u8*)dsi, dsi_len, GF_FALSE);
721
0
      } else if (dsi_enh) {
722
0
        hvcc = gf_odf_hevc_cfg_read((u8*)dsi_enh, dsi_enh_len, GF_TRUE);
723
0
      }
724
0
      param_array = hvcc ? hvcc->param_array : NULL;
725
0
      sps_nut = GF_HEVC_NALU_SEQ_PARAM;
726
0
      pps_nut = GF_HEVC_NALU_PIC_PARAM;
727
0
      vps_nut = GF_HEVC_NALU_VID_PARAM;
728
0
    }
729
730
0
    if (param_array) {
731
0
      u32 count, i, j, b64s;
732
0
      char b64[200];
733
0
      snprintf(tmp_buf, 100, "a=fmtp:%d", rtp->packetizer->PayloadType);
734
0
      gf_dynstrcat(out_sdp_buffer, tmp_buf, NULL);
735
736
0
      count = gf_list_count(param_array);
737
0
      for (i = 0; i < count; i++) {
738
0
        GF_NALUFFParamArray *ar = (GF_NALUFFParamArray *)gf_list_get(param_array, i);
739
0
        if (ar->type==sps_nut) {
740
0
          gf_dynstrcat(out_sdp_buffer, "; sprop-sps=", NULL);
741
0
        } else if (ar->type==pps_nut) {
742
0
          gf_dynstrcat(out_sdp_buffer, "; sprop-pps=", NULL);
743
0
        } else if (ar->type==vps_nut) {
744
0
          gf_dynstrcat(out_sdp_buffer, "; sprop-vps=", NULL);
745
0
        }
746
0
        for (j = 0; j < gf_list_count(ar->nalus); j++) {
747
0
          GF_NALUFFParam *sl = (GF_NALUFFParam *)gf_list_get(ar->nalus, j);
748
0
          b64s = gf_base64_encode(sl->data, sl->size, b64, 200);
749
0
          b64[b64s]=0;
750
0
          if (j) gf_dynstrcat(out_sdp_buffer, ", ", NULL);
751
0
          gf_dynstrcat(out_sdp_buffer, b64, NULL);
752
0
        }
753
0
      }
754
0
      if (vvcc) gf_odf_vvc_cfg_del(vvcc);
755
0
      if (hvcc) gf_odf_hevc_cfg_del(hvcc);
756
0
      gf_dynstrcat(out_sdp_buffer, "\n", NULL);
757
0
    }
758
0
  }
759
  /*MPEG-4 decoder config*/
760
0
  else if (rtp->packetizer->rtp_payt==GF_RTP_PAYT_MPEG4) {
761
0
    char *sdp = NULL;
762
0
    gf_rtp_builder_format_sdp(rtp->packetizer, payloadName, &sdp, (u8*)dsi, dsi_len);
763
0
    gf_dynstrcat(out_sdp_buffer, sdp, NULL);
764
0
    gf_dynstrcat(out_sdp_buffer, "\n", NULL);
765
0
    if (sdp) gf_free(sdp);
766
767
0
    if (rtp->packetizer->slMap.IV_length && KMS_URI) {
768
0
      if (!strnicmp(KMS_URI, "(key)", 5) || !strnicmp(KMS_URI, "(ipmp)", 6) || !strnicmp(KMS_URI, "(uri)", 5)) {
769
0
        gf_dynstrcat(out_sdp_buffer, "; ISMACrypKey=", NULL);
770
0
      } else {
771
0
        gf_dynstrcat(out_sdp_buffer, "; ISMACrypKey=(uri)", NULL);
772
0
      }
773
0
      gf_dynstrcat(out_sdp_buffer, KMS_URI, NULL);
774
0
      gf_dynstrcat(out_sdp_buffer, "\n", NULL);
775
0
    }
776
0
  }
777
#if GPAC_ENABLE_3GPP_DIMS_RTP
778
  /*DIMS decoder config*/
779
  else if (rtp->packetizer->rtp_payt==GF_RTP_PAYT_3GPP_DIMS) {
780
    snprintf(tmp_buf, 100, "a=fmtp:%d Version-profile=%d", rtp->packetizer->PayloadType, 10);
781
    gf_dynstrcat(out_sdp_buffer, tmp_buf, NULL);
782
    if (rtp->packetizer->flags & GP_RTP_DIMS_COMPRESSED) {
783
      gf_dynstrcat(out_sdp_buffer, ";content-coding=deflate", NULL);
784
    }
785
    gf_dynstrcat(out_sdp_buffer, "\n", NULL);
786
  }
787
#endif
788
  /*MPEG-4 Audio LATM*/
789
0
  else if (rtp->packetizer->rtp_payt==GF_RTP_PAYT_LATM) {
790
0
    GF_BitStream *bs;
791
0
    u8 *config_bytes;
792
0
    u32 config_size;
793
794
    /* form config string */
795
0
    bs = gf_bs_new(NULL, 32, GF_BITSTREAM_WRITE);
796
0
    gf_bs_write_int(bs, 0, 1); /* AudioMuxVersion */
797
0
    gf_bs_write_int(bs, 1, 1); /* all streams same time */
798
0
    gf_bs_write_int(bs, 0, 6); /* numSubFrames */
799
0
    gf_bs_write_int(bs, 0, 4); /* numPrograms */
800
0
    gf_bs_write_int(bs, 0, 3); /* numLayer */
801
802
    /* audio-specific config  - PacketVideo patch: don't signal SBR and PS stuff, not allowed in LATM with audioMuxVersion=0*/
803
0
    if (dsi) gf_bs_write_data(bs, dsi, MIN(dsi_len, 2) );
804
805
    /* other data */
806
0
    gf_bs_write_int(bs, 0, 3); /* frameLengthType */
807
0
    gf_bs_write_int(bs, 0xff, 8); /* latmBufferFullness */
808
0
    gf_bs_write_int(bs, 0, 1); /* otherDataPresent */
809
0
    gf_bs_write_int(bs, 0, 1); /* crcCheckPresent */
810
0
    gf_bs_get_content(bs, &config_bytes, &config_size);
811
0
    gf_bs_del(bs);
812
813
0
    char *sdp = NULL;
814
0
    gf_rtp_builder_format_sdp(rtp->packetizer, payloadName, &sdp, config_bytes, config_size);
815
0
    gf_free(config_bytes);
816
0
    gf_dynstrcat(out_sdp_buffer, sdp, NULL);
817
0
    gf_dynstrcat(out_sdp_buffer, "\n", NULL);
818
0
    if (sdp) gf_free(sdp);
819
0
  }
820
0
  return GF_OK;
821
0
}
822
823
824
825
GF_EXPORT
826
char *gf_rtp_streamer_format_sdp_header(char *app_name, char *ip_dest, char *session_name, char *iod64)
827
0
{
828
0
  u64 size;
829
0
  char *sdp, *tmp_fn = NULL;
830
0
  FILE *tmp = gf_file_temp(&tmp_fn);
831
0
  if (!tmp) return NULL;
832
833
  /* write SDP header*/
834
0
  gf_fprintf(tmp, "v=0\n");
835
0
  gf_fprintf(tmp, "o=%s 3326096807 1117107880000 IN IP%d %s\n", app_name, gf_net_is_ipv6(ip_dest) ? 6 : 4, ip_dest);
836
0
  gf_fprintf(tmp, "s=%s\n", (session_name ? session_name : "GPAC Scene Streaming Session"));
837
0
  gf_fprintf(tmp, "c=IN IP%d %s\n", gf_net_is_ipv6(ip_dest) ? 6 : 4, ip_dest);
838
0
  gf_fprintf(tmp, "t=0 0\n");
839
840
0
  if (iod64)
841
0
    gf_fprintf(tmp, "a=mpeg4-iod:\"data:application/mpeg4-iod;base64,%s\"\n", iod64);
842
843
0
  size = gf_fsize(tmp);
844
0
  sdp = (char*)gf_malloc(sizeof(char) * (size_t)(size+1));
845
0
  size = gf_fread(sdp, (size_t)size, tmp);
846
0
  sdp[size] = 0;
847
0
  gf_fclose(tmp);
848
0
  gf_file_delete(tmp_fn);
849
0
  gf_free(tmp_fn);
850
0
  return sdp;
851
0
}
852
853
GF_EXPORT
854
GF_Err gf_rtp_streamer_append_sdp(GF_RTPStreamer *rtp, u16 ESID, const u8 *dsi, u32 dsi_len, char *KMS_URI, char **out_sdp_buffer)
855
0
{
856
0
  return gf_rtp_streamer_append_sdp_extended(rtp, ESID, dsi, dsi_len, NULL, 0, KMS_URI, 0, 0, 0, 0, 0, 0, 0, 0, GF_FALSE, out_sdp_buffer);
857
0
}
858
859
GF_EXPORT
860
GF_Err gf_rtp_streamer_send_data(GF_RTPStreamer *rtp, u8 *data, u32 size, u32 fullsize, u64 cts, u64 dts, Bool is_rap, Bool au_start, Bool au_end, u32 au_sn, u32 sampleDuration, u32 sampleDescIndex)
861
0
{
862
0
  GF_Err e;
863
0
  if (!rtp->channel) return data ? GF_BAD_PARAM : GF_EOS;
864
865
0
  rtp->packetizer->sl_header.compositionTimeStamp = gf_timestamp_rescale(cts, rtp->in_timescale, rtp->channel->TimeScale);
866
0
  rtp->packetizer->sl_header.decodingTimeStamp = gf_timestamp_rescale(dts, rtp->in_timescale, rtp->channel->TimeScale);
867
0
  rtp->packetizer->sl_header.randomAccessPointFlag = is_rap;
868
0
  rtp->packetizer->sl_header.accessUnitStartFlag = au_start;
869
0
  rtp->packetizer->sl_header.accessUnitEndFlag = au_end;
870
0
  rtp->packetizer->sl_header.AU_sequenceNumber = au_sn;
871
0
  sampleDuration = (u32) gf_timestamp_rescale(sampleDuration, rtp->in_timescale, rtp->channel->TimeScale);
872
0
  if (au_start && size) rtp->packetizer->nb_aus++;
873
874
0
  rtp->last_err = GF_OK;
875
0
  e = gf_rtp_builder_process(rtp->packetizer, data, size, (u8) au_end, fullsize, sampleDuration, sampleDescIndex);
876
0
  if (e) return e;
877
0
  return rtp->last_err;
878
0
}
879
880
GF_EXPORT
881
GF_Err gf_rtp_streamer_send_au(GF_RTPStreamer *rtp, u8 *data, u32 size, u64 cts, u64 dts, Bool is_rap)
882
0
{
883
0
  return gf_rtp_streamer_send_data(rtp, data, size, size, cts, dts, is_rap, GF_TRUE, GF_TRUE, 0, 0, 0);
884
0
}
885
886
GF_EXPORT
887
GF_Err gf_rtp_streamer_send_au_with_sn(GF_RTPStreamer *rtp, u8 *data, u32 size, u64 cts, u64 dts, Bool is_rap, u32 inc_au_sn)
888
0
{
889
0
  if (inc_au_sn) rtp->packetizer->sl_header.AU_sequenceNumber += inc_au_sn;
890
0
  return gf_rtp_streamer_send_data(rtp, data, size, size, cts, dts, is_rap, GF_TRUE, GF_TRUE, rtp->packetizer->sl_header.AU_sequenceNumber, 0, 0);
891
0
}
892
893
GF_EXPORT
894
void gf_rtp_streamer_disable_auto_rtcp(GF_RTPStreamer *streamer)
895
0
{
896
0
  streamer->channel->no_auto_rtcp = GF_TRUE;
897
0
}
898
899
GF_EXPORT
900
GF_Err gf_rtp_streamer_send_rtcp(GF_RTPStreamer *streamer, Bool force_ts, u32 rtp_ts, u32 force_ntp_type, u32 ntp_sec, u32 ntp_frac)
901
0
{
902
0
  if (force_ts) streamer->channel->last_pck_ts = rtp_ts;
903
0
  if (force_ntp_type) {
904
0
    streamer->channel->forced_ntp_sec = ntp_sec;
905
0
    streamer->channel->forced_ntp_frac = ntp_frac;
906
0
    if (force_ntp_type==2) {
907
0
      streamer->channel->next_report_time = 0;
908
0
    }
909
    //we are sendind RTCP before first packet was sent, set sent time to same values
910
0
    if (!streamer->channel->last_pck_ntp_sec) {
911
0
      streamer->channel->last_pck_ntp_sec = ntp_sec;
912
0
      streamer->channel->last_pck_ntp_frac = ntp_frac;
913
0
    }
914
0
  } else {
915
0
    streamer->channel->forced_ntp_sec = 0;
916
0
    streamer->channel->forced_ntp_frac = 0;
917
0
  }
918
919
0
  GF_Err e = gf_rtp_send_rtcp_report(streamer->channel);
920
0
  if (force_ntp_type) {
921
0
    streamer->channel->forced_ntp_sec = 0;
922
0
    streamer->channel->forced_ntp_frac = 0;
923
0
  }
924
0
  return e;
925
0
}
926
927
GF_EXPORT
928
GF_Err gf_rtp_streamer_send_bye(GF_RTPStreamer *streamer)
929
0
{
930
0
  if (!streamer->channel) return GF_OK;
931
0
  return gf_rtp_send_bye(streamer->channel);
932
0
}
933
934
GF_EXPORT
935
u8 gf_rtp_streamer_get_payload_type(GF_RTPStreamer *streamer)
936
0
{
937
0
  return streamer ? streamer->packetizer->PayloadType : 0;
938
0
}
939
940
GF_EXPORT
941
u16 gf_rtp_streamer_get_next_rtp_sn(GF_RTPStreamer *streamer)
942
0
{
943
0
  return streamer->packetizer->rtp_header.SequenceNumber+1;
944
0
}
945
946
GF_EXPORT
947
GF_Err gf_rtp_streamer_set_interleave_callbacks(GF_RTPStreamer *streamer, gf_rtp_tcp_callback RTP_TCPCallback, void *cbk1, void *cbk2)
948
0
{
949
950
0
  return gf_rtp_set_interleave_callbacks(streamer->channel, RTP_TCPCallback, cbk1, cbk2);
951
0
}
952
953
GF_EXPORT
954
GF_Err gf_rtp_streamer_read_rtcp(GF_RTPStreamer *streamer, gf_rtcp_rr_callback rtcp_cbk, void *udta)
955
0
{
956
0
  u32 i, frac, sec;
957
0
  u32 size = gf_rtp_read_rtcp(streamer->channel, streamer->rtcp_buf, RTCP_BUF_SIZE);
958
0
  if (!size || !rtcp_cbk) return GF_EOS;
959
960
0
  gf_net_get_ntp(&sec, &frac);
961
0
  GF_Err e = gf_rtp_decode_rtcp(streamer->channel, streamer->rtcp_buf, size, NULL);
962
0
  if (e<0) return e;
963
964
0
  for (i=0; i<streamer->channel->nb_rctp_rr; i++) {
965
0
    GF_RTCP_Report *rr = &streamer->channel->rtcp_rr[i];
966
0
    u32 ssrc = (rr->ssrc==streamer->channel->SSRC) ? 0 : rr->ssrc;
967
0
    u32 lsr_sec = rr->last_sr>>16;
968
0
    u32 lsr_frac = (rr->last_sr&0xFFFF)<<16;
969
0
    u64 dlsr = rr->delay_last_sr * 1000;
970
0
    dlsr /= 65536;
971
0
    s64 diff = (sec&0x0000FFFF) * 1000;
972
0
    diff -= lsr_sec*1000;
973
0
    diff += ((frac>>16)*1000)/65536;
974
0
    diff -= (lsr_frac*1000)/65536;
975
0
    diff -= dlsr;
976
977
0
    u32 rtt_ms = (diff>=0) ? (u32) diff : 0;
978
0
    u32 loss_rate = (rr->frac_lost*1000)/255;
979
980
0
    rtcp_cbk(udta, ssrc, rtt_ms, rr->jitter, loss_rate);
981
0
  }
982
0
  return GF_OK;
983
0
}
984
985
GF_EXPORT
986
u32 gf_rtp_streamer_get_ssrc(GF_RTPStreamer *streamer)
987
0
{
988
0
  return (streamer && streamer->channel) ? streamer->channel->SSRC : 0;
989
0
}
990
991
GF_EXPORT
992
u32 gf_rtp_streamer_get_timescale(GF_RTPStreamer *streamer)
993
0
{
994
0
  return (streamer && streamer->packetizer) ? streamer->packetizer->sl_config.timestampResolution : 0;
995
0
}
996
997
GF_EXPORT
998
u32 gf_rtp_streamer_get_codecid(GF_RTPStreamer *streamer)
999
0
{
1000
0
  return (streamer && streamer->packetizer) ? streamer->packetizer->slMap.CodecID : 0 ;
1001
0
}
1002
1003
#endif /*GPAC_DISABLE_STREAMING && GPAC_DISABLE_ISOM*/
1004