~ubuntu-branches/ubuntu/lucid/psimedia/lucid-proposed

« back to all changes in this revision

Viewing changes to gstprovider/gstelements/rtpmanager/rtpsource.c

  • Committer: Bazaar Package Importer
  • Author(s): Ivan Borzenkov
  • Date: 2009-07-18 16:51:30 UTC
  • Revision ID: james.westby@ubuntu.com-20090718165130-7aetrkp6zivus4lk
Tags: upstream-1.0.3
ImportĀ upstreamĀ versionĀ 1.0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GStreamer
 
2
 * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
 
3
 *
 
4
 * This library is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU Library General Public
 
6
 * License as published by the Free Software Foundation; either
 
7
 * version 2 of the License, or (at your option) any later version.
 
8
 *
 
9
 * This library is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * Library General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Library General Public
 
15
 * License along with this library; if not, write to the
 
16
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
17
 * Boston, MA 02111-1307, USA.
 
18
 */
 
19
#include <string.h>
 
20
 
 
21
#include <gst/rtp/gstrtpbuffer.h>
 
22
#include <gst/rtp/gstrtcpbuffer.h>
 
23
 
 
24
#include "rtpsource.h"
 
25
 
 
26
GST_DEBUG_CATEGORY_STATIC (rtp_source_debug);
 
27
#define GST_CAT_DEFAULT rtp_source_debug
 
28
 
 
29
#define RTP_MAX_PROBATION_LEN   32
 
30
 
 
31
/* signals and args */
 
32
enum
 
33
{
 
34
  LAST_SIGNAL
 
35
};
 
36
 
 
37
#define DEFAULT_SSRC                 0
 
38
#define DEFAULT_IS_CSRC              FALSE
 
39
#define DEFAULT_IS_VALIDATED         FALSE
 
40
#define DEFAULT_IS_SENDER            FALSE
 
41
#define DEFAULT_SDES                 NULL
 
42
 
 
43
enum
 
44
{
 
45
  PROP_0,
 
46
  PROP_SSRC,
 
47
  PROP_IS_CSRC,
 
48
  PROP_IS_VALIDATED,
 
49
  PROP_IS_SENDER,
 
50
  PROP_SDES,
 
51
  PROP_STATS,
 
52
  PROP_LAST
 
53
};
 
54
 
 
55
/* GObject vmethods */
 
56
static void rtp_source_finalize (GObject * object);
 
57
static void rtp_source_set_property (GObject * object, guint prop_id,
 
58
    const GValue * value, GParamSpec * pspec);
 
59
static void rtp_source_get_property (GObject * object, guint prop_id,
 
60
    GValue * value, GParamSpec * pspec);
 
61
 
 
62
/* static guint rtp_source_signals[LAST_SIGNAL] = { 0 }; */
 
63
 
 
64
G_DEFINE_TYPE (RTPSource, rtp_source, G_TYPE_OBJECT);
 
65
 
 
66
static void
 
67
rtp_source_class_init (RTPSourceClass * klass)
 
68
{
 
69
  GObjectClass *gobject_class;
 
70
 
 
71
  gobject_class = (GObjectClass *) klass;
 
72
 
 
73
  gobject_class->finalize = rtp_source_finalize;
 
74
 
 
75
  gobject_class->set_property = rtp_source_set_property;
 
76
  gobject_class->get_property = rtp_source_get_property;
 
77
 
 
78
  g_object_class_install_property (gobject_class, PROP_SSRC,
 
79
      g_param_spec_uint ("ssrc", "SSRC",
 
80
          "The SSRC of this source", 0, G_MAXUINT, DEFAULT_SSRC,
 
81
          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
 
82
 
 
83
  g_object_class_install_property (gobject_class, PROP_IS_CSRC,
 
84
      g_param_spec_boolean ("is-csrc", "Is CSRC",
 
85
          "If this SSRC is acting as a contributing source",
 
86
          DEFAULT_IS_CSRC, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 
87
 
 
88
  g_object_class_install_property (gobject_class, PROP_IS_VALIDATED,
 
89
      g_param_spec_boolean ("is-validated", "Is Validated",
 
90
          "If this SSRC is validated", DEFAULT_IS_VALIDATED,
 
91
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 
92
 
 
93
  g_object_class_install_property (gobject_class, PROP_IS_SENDER,
 
94
      g_param_spec_boolean ("is-sender", "Is Sender",
 
95
          "If this SSRC is a sender", DEFAULT_IS_SENDER,
 
96
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 
97
 
 
98
  /**
 
99
   * RTPSource::sdes
 
100
   *
 
101
   * The current SDES items of the source. Returns a structure with the
 
102
   * following fields:
 
103
   *
 
104
   *  'cname'    G_TYPE_STRING  : The canonical name 
 
105
   *  'name'     G_TYPE_STRING  : The user name 
 
106
   *  'email'    G_TYPE_STRING  : The user's electronic mail address
 
107
   *  'phone'    G_TYPE_STRING  : The user's phone number
 
108
   *  'location' G_TYPE_STRING  : The geographic user location
 
109
   *  'tool'     G_TYPE_STRING  : The name of application or tool
 
110
   *  'note'     G_TYPE_STRING  : A notice about the source
 
111
   */
 
112
  g_object_class_install_property (gobject_class, PROP_SDES,
 
113
      g_param_spec_boxed ("sdes", "SDES",
 
114
          "The SDES information for this source",
 
115
          GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 
116
 
 
117
  /**
 
118
   * RTPSource::stats
 
119
   *
 
120
   * The statistics of the source. This property returns a GstStructure with
 
121
   * name application/x-rtp-source-stats with the following fields:
 
122
   * 
 
123
   */
 
124
  g_object_class_install_property (gobject_class, PROP_STATS,
 
125
      g_param_spec_boxed ("stats", "Stats",
 
126
          "The stats of this source", GST_TYPE_STRUCTURE,
 
127
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 
128
 
 
129
  GST_DEBUG_CATEGORY_INIT (rtp_source_debug, "rtpsource", 0, "RTP Source");
 
130
}
 
131
 
 
132
/**
 
133
 * rtp_source_reset:
 
134
 * @src: an #RTPSource
 
135
 *
 
136
 * Reset the stats of @src.
 
137
 */
 
138
void
 
139
rtp_source_reset (RTPSource * src)
 
140
{
 
141
  src->received_bye = FALSE;
 
142
 
 
143
  src->stats.cycles = -1;
 
144
  src->stats.jitter = 0;
 
145
  src->stats.transit = -1;
 
146
  src->stats.curr_sr = 0;
 
147
  src->stats.curr_rr = 0;
 
148
}
 
149
 
 
150
static void
 
151
rtp_source_init (RTPSource * src)
 
152
{
 
153
  /* sources are initialy on probation until we receive enough valid RTP
 
154
   * packets or a valid RTCP packet */
 
155
  src->validated = FALSE;
 
156
  src->internal = FALSE;
 
157
  src->probation = RTP_DEFAULT_PROBATION;
 
158
 
 
159
  src->payload = -1;
 
160
  src->clock_rate = -1;
 
161
  src->packets = g_queue_new ();
 
162
  src->seqnum_base = -1;
 
163
  src->last_rtptime = -1;
 
164
 
 
165
  rtp_source_reset (src);
 
166
}
 
167
 
 
168
static void
 
169
rtp_source_finalize (GObject * object)
 
170
{
 
171
  RTPSource *src;
 
172
  GstBuffer *buffer;
 
173
  gint i;
 
174
 
 
175
  src = RTP_SOURCE_CAST (object);
 
176
 
 
177
  while ((buffer = g_queue_pop_head (src->packets)))
 
178
    gst_buffer_unref (buffer);
 
179
  g_queue_free (src->packets);
 
180
 
 
181
  for (i = 0; i < 9; i++)
 
182
    g_free (src->sdes[i]);
 
183
 
 
184
  g_free (src->bye_reason);
 
185
 
 
186
  gst_caps_replace (&src->caps, NULL);
 
187
 
 
188
  G_OBJECT_CLASS (rtp_source_parent_class)->finalize (object);
 
189
}
 
190
 
 
191
static GstStructure *
 
192
rtp_source_create_stats (RTPSource * src)
 
193
{
 
194
  GstStructure *s;
 
195
  gboolean is_sender = src->is_sender;
 
196
  gboolean internal = src->internal;
 
197
 
 
198
  /* common data for all types of sources */
 
199
  s = gst_structure_new ("application/x-rtp-source-stats",
 
200
      "ssrc", G_TYPE_UINT, (guint) src->ssrc,
 
201
      "internal", G_TYPE_BOOLEAN, internal,
 
202
      "validated", G_TYPE_BOOLEAN, src->validated,
 
203
      "received-bye", G_TYPE_BOOLEAN, src->received_bye,
 
204
      "is-csrc", G_TYPE_BOOLEAN, src->is_csrc,
 
205
      "is-sender", G_TYPE_BOOLEAN, is_sender, NULL);
 
206
 
 
207
  if (internal) {
 
208
    /* our internal source */
 
209
    if (is_sender) {
 
210
      /* if we are sending, report about how much we sent, other sources will
 
211
       * have a RB with info on reception. */
 
212
      gst_structure_set (s,
 
213
          "octets-sent", G_TYPE_UINT64, src->stats.octets_sent,
 
214
          "packets-sent", G_TYPE_UINT64, src->stats.packets_sent,
 
215
          "bitrate", G_TYPE_UINT64, src->bitrate, NULL);
 
216
    } else {
 
217
      /* if we are not sending we have nothing more to report */
 
218
    }
 
219
  } else {
 
220
    gboolean have_rb;
 
221
    guint8 fractionlost = 0;
 
222
    gint32 packetslost = 0;
 
223
    guint32 exthighestseq = 0;
 
224
    guint32 jitter = 0;
 
225
    guint32 lsr = 0;
 
226
    guint32 dlsr = 0;
 
227
    guint32 round_trip = 0;
 
228
 
 
229
    /* other sources */
 
230
    if (is_sender) {
 
231
      gboolean have_sr;
 
232
      GstClockTime time = 0;
 
233
      guint64 ntptime = 0;
 
234
      guint32 rtptime = 0;
 
235
      guint32 packet_count = 0;
 
236
      guint32 octet_count = 0;
 
237
 
 
238
      /* this source is sending to us, get the last SR. */
 
239
      have_sr = rtp_source_get_last_sr (src, &time, &ntptime, &rtptime,
 
240
          &packet_count, &octet_count);
 
241
      gst_structure_set (s,
 
242
          "octets-received", G_TYPE_UINT64, src->stats.octets_received,
 
243
          "packets-received", G_TYPE_UINT64, src->stats.packets_received,
 
244
          "have-sr", G_TYPE_BOOLEAN, have_sr,
 
245
          "sr-ntptime", G_TYPE_UINT64, ntptime,
 
246
          "sr-rtptime", G_TYPE_UINT, (guint) rtptime,
 
247
          "sr-octet-count", G_TYPE_UINT, (guint) octet_count,
 
248
          "sr-packet-count", G_TYPE_UINT, (guint) packet_count, NULL);
 
249
    }
 
250
    /* we might be sending to this SSRC so we report about how it is
 
251
     * receiving our data */
 
252
    have_rb = rtp_source_get_last_rb (src, &fractionlost, &packetslost,
 
253
        &exthighestseq, &jitter, &lsr, &dlsr, &round_trip);
 
254
 
 
255
    gst_structure_set (s,
 
256
        "have-rb", G_TYPE_BOOLEAN, have_rb,
 
257
        "rb-fractionlost", G_TYPE_UINT, (guint) fractionlost,
 
258
        "rb-packetslost", G_TYPE_INT, (gint) packetslost,
 
259
        "rb-exthighestseq", G_TYPE_UINT, (guint) exthighestseq,
 
260
        "rb-jitter", G_TYPE_UINT, (guint) jitter,
 
261
        "rb-lsr", G_TYPE_UINT, (guint) lsr,
 
262
        "rb-dlsr", G_TYPE_UINT, (guint) dlsr,
 
263
        "rb-round-trip", G_TYPE_UINT, (guint) round_trip, NULL);
 
264
  }
 
265
 
 
266
  return s;
 
267
}
 
268
 
 
269
static GstStructure *
 
270
rtp_source_create_sdes (RTPSource * src)
 
271
{
 
272
  GstStructure *s;
 
273
  gchar *str;
 
274
 
 
275
  s = gst_structure_new ("application/x-rtp-source-sdes", NULL);
 
276
 
 
277
  if ((str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_CNAME))) {
 
278
    gst_structure_set (s, "cname", G_TYPE_STRING, str, NULL);
 
279
    g_free (str);
 
280
  }
 
281
  if ((str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_NAME))) {
 
282
    gst_structure_set (s, "name", G_TYPE_STRING, str, NULL);
 
283
    g_free (str);
 
284
  }
 
285
  if ((str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_EMAIL))) {
 
286
    gst_structure_set (s, "email", G_TYPE_STRING, str, NULL);
 
287
    g_free (str);
 
288
  }
 
289
  if ((str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_PHONE))) {
 
290
    gst_structure_set (s, "phone", G_TYPE_STRING, str, NULL);
 
291
    g_free (str);
 
292
  }
 
293
  if ((str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_LOC))) {
 
294
    gst_structure_set (s, "location", G_TYPE_STRING, str, NULL);
 
295
    g_free (str);
 
296
  }
 
297
  if ((str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_TOOL))) {
 
298
    gst_structure_set (s, "tool", G_TYPE_STRING, str, NULL);
 
299
    g_free (str);
 
300
  }
 
301
  if ((str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_NOTE))) {
 
302
    gst_structure_set (s, "note", G_TYPE_STRING, str, NULL);
 
303
    g_free (str);
 
304
  }
 
305
  return s;
 
306
}
 
307
 
 
308
static void
 
309
rtp_source_set_property (GObject * object, guint prop_id,
 
310
    const GValue * value, GParamSpec * pspec)
 
311
{
 
312
  RTPSource *src;
 
313
 
 
314
  src = RTP_SOURCE (object);
 
315
 
 
316
  switch (prop_id) {
 
317
    case PROP_SSRC:
 
318
      src->ssrc = g_value_get_uint (value);
 
319
      break;
 
320
    default:
 
321
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
322
      break;
 
323
  }
 
324
}
 
325
 
 
326
static void
 
327
rtp_source_get_property (GObject * object, guint prop_id,
 
328
    GValue * value, GParamSpec * pspec)
 
329
{
 
330
  RTPSource *src;
 
331
 
 
332
  src = RTP_SOURCE (object);
 
333
 
 
334
  switch (prop_id) {
 
335
    case PROP_SSRC:
 
336
      g_value_set_uint (value, rtp_source_get_ssrc (src));
 
337
      break;
 
338
    case PROP_IS_CSRC:
 
339
      g_value_set_boolean (value, rtp_source_is_as_csrc (src));
 
340
      break;
 
341
    case PROP_IS_VALIDATED:
 
342
      g_value_set_boolean (value, rtp_source_is_validated (src));
 
343
      break;
 
344
    case PROP_IS_SENDER:
 
345
      g_value_set_boolean (value, rtp_source_is_sender (src));
 
346
      break;
 
347
    case PROP_SDES:
 
348
      g_value_take_boxed (value, rtp_source_create_sdes (src));
 
349
      break;
 
350
    case PROP_STATS:
 
351
      g_value_take_boxed (value, rtp_source_create_stats (src));
 
352
      break;
 
353
    default:
 
354
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
355
      break;
 
356
  }
 
357
}
 
358
 
 
359
/**
 
360
 * rtp_source_new:
 
361
 * @ssrc: an SSRC
 
362
 *
 
363
 * Create a #RTPSource with @ssrc.
 
364
 *
 
365
 * Returns: a new #RTPSource. Use g_object_unref() after usage.
 
366
 */
 
367
RTPSource *
 
368
rtp_source_new (guint32 ssrc)
 
369
{
 
370
  RTPSource *src;
 
371
 
 
372
  src = g_object_new (RTP_TYPE_SOURCE, NULL);
 
373
  src->ssrc = ssrc;
 
374
 
 
375
  return src;
 
376
}
 
377
 
 
378
/**
 
379
 * rtp_source_set_callbacks:
 
380
 * @src: an #RTPSource
 
381
 * @cb: callback functions
 
382
 * @user_data: user data
 
383
 *
 
384
 * Set the callbacks for the source.
 
385
 */
 
386
void
 
387
rtp_source_set_callbacks (RTPSource * src, RTPSourceCallbacks * cb,
 
388
    gpointer user_data)
 
389
{
 
390
  g_return_if_fail (RTP_IS_SOURCE (src));
 
391
 
 
392
  src->callbacks.push_rtp = cb->push_rtp;
 
393
  src->callbacks.clock_rate = cb->clock_rate;
 
394
  src->user_data = user_data;
 
395
}
 
396
 
 
397
/**
 
398
 * rtp_source_get_ssrc:
 
399
 * @src: an #RTPSource
 
400
 *
 
401
 * Get the SSRC of @source.
 
402
 *
 
403
 * Returns: the SSRC of src.
 
404
 */
 
405
guint32
 
406
rtp_source_get_ssrc (RTPSource * src)
 
407
{
 
408
  guint32 result;
 
409
 
 
410
  g_return_val_if_fail (RTP_IS_SOURCE (src), 0);
 
411
 
 
412
  result = src->ssrc;
 
413
 
 
414
  return result;
 
415
}
 
416
 
 
417
/**
 
418
 * rtp_source_set_as_csrc:
 
419
 * @src: an #RTPSource
 
420
 *
 
421
 * Configure @src as a CSRC, this will also validate @src.
 
422
 */
 
423
void
 
424
rtp_source_set_as_csrc (RTPSource * src)
 
425
{
 
426
  g_return_if_fail (RTP_IS_SOURCE (src));
 
427
 
 
428
  src->validated = TRUE;
 
429
  src->is_csrc = TRUE;
 
430
}
 
431
 
 
432
/**
 
433
 * rtp_source_is_as_csrc:
 
434
 * @src: an #RTPSource
 
435
 *
 
436
 * Check if @src is a contributing source.
 
437
 *
 
438
 * Returns: %TRUE if @src is acting as a contributing source.
 
439
 */
 
440
gboolean
 
441
rtp_source_is_as_csrc (RTPSource * src)
 
442
{
 
443
  gboolean result;
 
444
 
 
445
  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
 
446
 
 
447
  result = src->is_csrc;
 
448
 
 
449
  return result;
 
450
}
 
451
 
 
452
/**
 
453
 * rtp_source_is_active:
 
454
 * @src: an #RTPSource
 
455
 *
 
456
 * Check if @src is an active source. A source is active if it has been
 
457
 * validated and has not yet received a BYE packet
 
458
 *
 
459
 * Returns: %TRUE if @src is an qactive source.
 
460
 */
 
461
gboolean
 
462
rtp_source_is_active (RTPSource * src)
 
463
{
 
464
  gboolean result;
 
465
 
 
466
  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
 
467
 
 
468
  result = RTP_SOURCE_IS_ACTIVE (src);
 
469
 
 
470
  return result;
 
471
}
 
472
 
 
473
/**
 
474
 * rtp_source_is_validated:
 
475
 * @src: an #RTPSource
 
476
 *
 
477
 * Check if @src is a validated source.
 
478
 *
 
479
 * Returns: %TRUE if @src is a validated source.
 
480
 */
 
481
gboolean
 
482
rtp_source_is_validated (RTPSource * src)
 
483
{
 
484
  gboolean result;
 
485
 
 
486
  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
 
487
 
 
488
  result = src->validated;
 
489
 
 
490
  return result;
 
491
}
 
492
 
 
493
/**
 
494
 * rtp_source_is_sender:
 
495
 * @src: an #RTPSource
 
496
 *
 
497
 * Check if @src is a sending source.
 
498
 *
 
499
 * Returns: %TRUE if @src is a sending source.
 
500
 */
 
501
gboolean
 
502
rtp_source_is_sender (RTPSource * src)
 
503
{
 
504
  gboolean result;
 
505
 
 
506
  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
 
507
 
 
508
  result = RTP_SOURCE_IS_SENDER (src);
 
509
 
 
510
  return result;
 
511
}
 
512
 
 
513
/**
 
514
 * rtp_source_received_bye:
 
515
 * @src: an #RTPSource
 
516
 *
 
517
 * Check if @src has receoved a BYE packet.
 
518
 *
 
519
 * Returns: %TRUE if @src has received a BYE packet.
 
520
 */
 
521
gboolean
 
522
rtp_source_received_bye (RTPSource * src)
 
523
{
 
524
  gboolean result;
 
525
 
 
526
  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
 
527
 
 
528
  result = src->received_bye;
 
529
 
 
530
  return result;
 
531
}
 
532
 
 
533
 
 
534
/**
 
535
 * rtp_source_get_bye_reason:
 
536
 * @src: an #RTPSource
 
537
 *
 
538
 * Get the BYE reason for @src. Check if the source receoved a BYE message first
 
539
 * with rtp_source_received_bye().
 
540
 *
 
541
 * Returns: The BYE reason or NULL when no reason was given or the source did
 
542
 * not receive a BYE message yet. g_fee() after usage.
 
543
 */
 
544
gchar *
 
545
rtp_source_get_bye_reason (RTPSource * src)
 
546
{
 
547
  gchar *result;
 
548
 
 
549
  g_return_val_if_fail (RTP_IS_SOURCE (src), NULL);
 
550
 
 
551
  result = g_strdup (src->bye_reason);
 
552
 
 
553
  return result;
 
554
}
 
555
 
 
556
/**
 
557
 * rtp_source_update_caps:
 
558
 * @src: an #RTPSource
 
559
 * @caps: a #GstCaps
 
560
 *
 
561
 * Parse @caps and store all relevant information in @source.
 
562
 */
 
563
void
 
564
rtp_source_update_caps (RTPSource * src, GstCaps * caps)
 
565
{
 
566
  GstStructure *s;
 
567
  guint val;
 
568
  gint ival;
 
569
 
 
570
  /* nothing changed, return */
 
571
  if (src->caps == caps)
 
572
    return;
 
573
 
 
574
  s = gst_caps_get_structure (caps, 0);
 
575
 
 
576
  if (gst_structure_get_int (s, "payload", &ival))
 
577
    src->payload = ival;
 
578
  else
 
579
    src->payload = -1;
 
580
  GST_DEBUG ("got payload %d", src->payload);
 
581
 
 
582
  if (gst_structure_get_int (s, "clock-rate", &ival))
 
583
    src->clock_rate = ival;
 
584
  else
 
585
    src->clock_rate = -1;
 
586
 
 
587
  GST_DEBUG ("got clock-rate %d", src->clock_rate);
 
588
 
 
589
  if (gst_structure_get_uint (s, "seqnum-base", &val))
 
590
    src->seqnum_base = val;
 
591
  else
 
592
    src->seqnum_base = -1;
 
593
 
 
594
  GST_DEBUG ("got seqnum-base %" G_GINT32_FORMAT, src->seqnum_base);
 
595
 
 
596
  gst_caps_replace (&src->caps, caps);
 
597
}
 
598
 
 
599
/**
 
600
 * rtp_source_set_sdes:
 
601
 * @src: an #RTPSource
 
602
 * @type: the type of the SDES item
 
603
 * @data: the SDES data
 
604
 * @len: the SDES length
 
605
 *
 
606
 * Store an SDES item of @type in @src. 
 
607
 *
 
608
 * Returns: %FALSE if the SDES item was unchanged or @type is unknown.
 
609
 */
 
610
gboolean
 
611
rtp_source_set_sdes (RTPSource * src, GstRTCPSDESType type,
 
612
    const guint8 * data, guint len)
 
613
{
 
614
  guint8 *old;
 
615
 
 
616
  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
 
617
 
 
618
  if (type < 0 || type > GST_RTCP_SDES_PRIV)
 
619
    return FALSE;
 
620
 
 
621
  old = src->sdes[type];
 
622
 
 
623
  /* lengths are the same, check if the data is the same */
 
624
  if ((src->sdes_len[type] == len))
 
625
    if (data != NULL && old != NULL && (memcmp (old, data, len) == 0))
 
626
      return FALSE;
 
627
 
 
628
  /* NULL data, make sure we store 0 length or if no length is given,
 
629
   * take strlen */
 
630
  if (data == NULL)
 
631
    len = 0;
 
632
 
 
633
  g_free (src->sdes[type]);
 
634
  src->sdes[type] = g_memdup (data, len);
 
635
  src->sdes_len[type] = len;
 
636
 
 
637
  return TRUE;
 
638
}
 
639
 
 
640
/**
 
641
 * rtp_source_set_sdes_string:
 
642
 * @src: an #RTPSource
 
643
 * @type: the type of the SDES item
 
644
 * @data: the SDES data
 
645
 *
 
646
 * Store an SDES item of @type in @src. This function is similar to
 
647
 * rtp_source_set_sdes() but takes a null-terminated string for convenience.
 
648
 *
 
649
 * Returns: %FALSE if the SDES item was unchanged or @type is unknown.
 
650
 */
 
651
gboolean
 
652
rtp_source_set_sdes_string (RTPSource * src, GstRTCPSDESType type,
 
653
    const gchar * data)
 
654
{
 
655
  guint len;
 
656
  gboolean result;
 
657
 
 
658
  if (data)
 
659
    len = strlen (data);
 
660
  else
 
661
    len = 0;
 
662
 
 
663
  result = rtp_source_set_sdes (src, type, (guint8 *) data, len);
 
664
 
 
665
  return result;
 
666
}
 
667
 
 
668
/**
 
669
 * rtp_source_get_sdes:
 
670
 * @src: an #RTPSource
 
671
 * @type: the type of the SDES item
 
672
 * @data: location to store the SDES data or NULL
 
673
 * @len: location to store the SDES length or NULL
 
674
 *
 
675
 * Get the SDES item of @type from @src. Note that @data does not always point
 
676
 * to a null-terminated string, use rtp_source_get_sdes_string() to retrieve a
 
677
 * null-terminated string instead.
 
678
 *
 
679
 * @data remains valid until the next call to rtp_source_set_sdes().
 
680
 *
 
681
 * Returns: %TRUE if @type was valid and @data and @len contain valid
 
682
 * data. @data can be NULL when the item was unset.
 
683
 */
 
684
gboolean
 
685
rtp_source_get_sdes (RTPSource * src, GstRTCPSDESType type, guint8 ** data,
 
686
    guint * len)
 
687
{
 
688
  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
 
689
 
 
690
  if (type < 0 || type > GST_RTCP_SDES_PRIV)
 
691
    return FALSE;
 
692
 
 
693
  if (data)
 
694
    *data = src->sdes[type];
 
695
  if (len)
 
696
    *len = src->sdes_len[type];
 
697
 
 
698
  return TRUE;
 
699
}
 
700
 
 
701
/**
 
702
 * rtp_source_get_sdes_string:
 
703
 * @src: an #RTPSource
 
704
 * @type: the type of the SDES item
 
705
 *
 
706
 * Get the SDES item of @type from @src. 
 
707
 *
 
708
 * Returns: a null-terminated copy of the SDES item or NULL when @type was not
 
709
 * valid or the SDES item was unset. g_free() after usage.
 
710
 */
 
711
gchar *
 
712
rtp_source_get_sdes_string (RTPSource * src, GstRTCPSDESType type)
 
713
{
 
714
  gchar *result;
 
715
 
 
716
  g_return_val_if_fail (RTP_IS_SOURCE (src), NULL);
 
717
 
 
718
  if (type < 0 || type > GST_RTCP_SDES_PRIV)
 
719
    return NULL;
 
720
 
 
721
  result = g_strndup ((const gchar *) src->sdes[type], src->sdes_len[type]);
 
722
 
 
723
  return result;
 
724
}
 
725
 
 
726
/**
 
727
 * rtp_source_set_rtp_from:
 
728
 * @src: an #RTPSource
 
729
 * @address: the RTP address to set
 
730
 *
 
731
 * Set that @src is receiving RTP packets from @address. This is used for
 
732
 * collistion checking.
 
733
 */
 
734
void
 
735
rtp_source_set_rtp_from (RTPSource * src, GstNetAddress * address)
 
736
{
 
737
  g_return_if_fail (RTP_IS_SOURCE (src));
 
738
 
 
739
  src->have_rtp_from = TRUE;
 
740
  memcpy (&src->rtp_from, address, sizeof (GstNetAddress));
 
741
}
 
742
 
 
743
/**
 
744
 * rtp_source_set_rtcp_from:
 
745
 * @src: an #RTPSource
 
746
 * @address: the RTCP address to set
 
747
 *
 
748
 * Set that @src is receiving RTCP packets from @address. This is used for
 
749
 * collistion checking.
 
750
 */
 
751
void
 
752
rtp_source_set_rtcp_from (RTPSource * src, GstNetAddress * address)
 
753
{
 
754
  g_return_if_fail (RTP_IS_SOURCE (src));
 
755
 
 
756
  src->have_rtcp_from = TRUE;
 
757
  memcpy (&src->rtcp_from, address, sizeof (GstNetAddress));
 
758
}
 
759
 
 
760
static GstFlowReturn
 
761
push_packet (RTPSource * src, GstBuffer * buffer)
 
762
{
 
763
  GstFlowReturn ret = GST_FLOW_OK;
 
764
 
 
765
  /* push queued packets first if any */
 
766
  while (!g_queue_is_empty (src->packets)) {
 
767
    GstBuffer *buffer = GST_BUFFER_CAST (g_queue_pop_head (src->packets));
 
768
 
 
769
    GST_LOG ("pushing queued packet");
 
770
    if (src->callbacks.push_rtp)
 
771
      src->callbacks.push_rtp (src, buffer, src->user_data);
 
772
    else
 
773
      gst_buffer_unref (buffer);
 
774
  }
 
775
  GST_LOG ("pushing new packet");
 
776
  /* push packet */
 
777
  if (src->callbacks.push_rtp)
 
778
    ret = src->callbacks.push_rtp (src, buffer, src->user_data);
 
779
  else
 
780
    gst_buffer_unref (buffer);
 
781
 
 
782
  return ret;
 
783
}
 
784
 
 
785
static gint
 
786
get_clock_rate (RTPSource * src, guint8 payload)
 
787
{
 
788
  if (src->payload == -1) {
 
789
    /* first payload received, nothing was in the caps, lock on to this payload */
 
790
    src->payload = payload;
 
791
    GST_DEBUG ("first payload %d", payload);
 
792
  } else if (payload != src->payload) {
 
793
    /* we have a different payload than before, reset the clock-rate */
 
794
    GST_DEBUG ("new payload %d", payload);
 
795
    src->payload = payload;
 
796
    src->clock_rate = -1;
 
797
    src->stats.transit = -1;
 
798
  }
 
799
 
 
800
  if (src->clock_rate == -1) {
 
801
    gint clock_rate = -1;
 
802
 
 
803
    if (src->callbacks.clock_rate)
 
804
      clock_rate = src->callbacks.clock_rate (src, payload, src->user_data);
 
805
 
 
806
    GST_DEBUG ("got clock-rate %d", clock_rate);
 
807
 
 
808
    src->clock_rate = clock_rate;
 
809
  }
 
810
  return src->clock_rate;
 
811
}
 
812
 
 
813
/* Jitter is the variation in the delay of received packets in a flow. It is
 
814
 * measured by comparing the interval when RTP packets were sent to the interval
 
815
 * at which they were received. For instance, if packet #1 and packet #2 leave
 
816
 * 50 milliseconds apart and arrive 60 milliseconds apart, then the jitter is 10
 
817
 * milliseconds. */
 
818
static void
 
819
calculate_jitter (RTPSource * src, GstBuffer * buffer,
 
820
    RTPArrivalStats * arrival)
 
821
{
 
822
  guint64 ntpnstime;
 
823
  guint32 rtparrival, transit, rtptime;
 
824
  gint32 diff;
 
825
  gint clock_rate;
 
826
  guint8 pt;
 
827
 
 
828
  /* get arrival time */
 
829
  if ((ntpnstime = arrival->ntpnstime) == GST_CLOCK_TIME_NONE)
 
830
    goto no_time;
 
831
 
 
832
  pt = gst_rtp_buffer_get_payload_type (buffer);
 
833
 
 
834
  GST_LOG ("SSRC %08x got payload %d", src->ssrc, pt);
 
835
 
 
836
  /* get clockrate */
 
837
  if ((clock_rate = get_clock_rate (src, pt)) == -1)
 
838
    goto no_clock_rate;
 
839
 
 
840
  rtptime = gst_rtp_buffer_get_timestamp (buffer);
 
841
 
 
842
  /* convert arrival time to RTP timestamp units, truncate to 32 bits, we don't
 
843
   * care about the absolute value, just the difference. */
 
844
  rtparrival = gst_util_uint64_scale_int (ntpnstime, clock_rate, GST_SECOND);
 
845
 
 
846
  /* transit time is difference with RTP timestamp */
 
847
  transit = rtparrival - rtptime;
 
848
 
 
849
  /* get ABS diff with previous transit time */
 
850
  if (src->stats.transit != -1) {
 
851
    if (transit > src->stats.transit)
 
852
      diff = transit - src->stats.transit;
 
853
    else
 
854
      diff = src->stats.transit - transit;
 
855
  } else
 
856
    diff = 0;
 
857
 
 
858
  src->stats.transit = transit;
 
859
 
 
860
  /* update jitter, the value we store is scaled up so we can keep precision. */
 
861
  src->stats.jitter += diff - ((src->stats.jitter + 8) >> 4);
 
862
 
 
863
  src->stats.prev_rtptime = src->stats.last_rtptime;
 
864
  src->stats.last_rtptime = rtparrival;
 
865
 
 
866
  GST_LOG ("rtparrival %u, rtptime %u, clock-rate %d, diff %d, jitter: %f",
 
867
      rtparrival, rtptime, clock_rate, diff, (src->stats.jitter) / 16.0);
 
868
 
 
869
  return;
 
870
 
 
871
  /* ERRORS */
 
872
no_time:
 
873
  {
 
874
    GST_WARNING ("cannot get current time");
 
875
    return;
 
876
  }
 
877
no_clock_rate:
 
878
  {
 
879
    GST_WARNING ("cannot get clock-rate for pt %d", pt);
 
880
    return;
 
881
  }
 
882
}
 
883
 
 
884
static void
 
885
init_seq (RTPSource * src, guint16 seq)
 
886
{
 
887
  src->stats.base_seq = seq;
 
888
  src->stats.max_seq = seq;
 
889
  src->stats.bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */
 
890
  src->stats.cycles = 0;
 
891
  src->stats.packets_received = 0;
 
892
  src->stats.octets_received = 0;
 
893
  src->stats.bytes_received = 0;
 
894
  src->stats.prev_received = 0;
 
895
  src->stats.prev_expected = 0;
 
896
 
 
897
  GST_DEBUG ("base_seq %d", seq);
 
898
}
 
899
 
 
900
/**
 
901
 * rtp_source_process_rtp:
 
902
 * @src: an #RTPSource
 
903
 * @buffer: an RTP buffer
 
904
 *
 
905
 * Let @src handle the incomming RTP @buffer.
 
906
 *
 
907
 * Returns: a #GstFlowReturn.
 
908
 */
 
909
GstFlowReturn
 
910
rtp_source_process_rtp (RTPSource * src, GstBuffer * buffer,
 
911
    RTPArrivalStats * arrival)
 
912
{
 
913
  GstFlowReturn result = GST_FLOW_OK;
 
914
  guint16 seqnr, udelta;
 
915
  RTPSourceStats *stats;
 
916
 
 
917
  g_return_val_if_fail (RTP_IS_SOURCE (src), GST_FLOW_ERROR);
 
918
  g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
 
919
 
 
920
  stats = &src->stats;
 
921
 
 
922
  seqnr = gst_rtp_buffer_get_seq (buffer);
 
923
 
 
924
  rtp_source_update_caps (src, GST_BUFFER_CAPS (buffer));
 
925
 
 
926
  if (stats->cycles == -1) {
 
927
    GST_DEBUG ("received first buffer");
 
928
    /* first time we heard of this source */
 
929
    init_seq (src, seqnr);
 
930
    src->stats.max_seq = seqnr - 1;
 
931
    src->probation = RTP_DEFAULT_PROBATION;
 
932
  }
 
933
 
 
934
  udelta = seqnr - stats->max_seq;
 
935
 
 
936
  /* if we are still on probation, check seqnum */
 
937
  if (src->probation) {
 
938
    guint16 expected;
 
939
 
 
940
    expected = src->stats.max_seq + 1;
 
941
 
 
942
    /* when in probation, we require consecutive seqnums */
 
943
    if (seqnr == expected) {
 
944
      /* expected packet */
 
945
      GST_DEBUG ("probation: seqnr %d == expected %d", seqnr, expected);
 
946
      src->probation--;
 
947
      src->stats.max_seq = seqnr;
 
948
      if (src->probation == 0) {
 
949
        GST_DEBUG ("probation done!");
 
950
        init_seq (src, seqnr);
 
951
      } else {
 
952
        GstBuffer *q;
 
953
 
 
954
        GST_DEBUG ("probation %d: queue buffer", src->probation);
 
955
        /* when still in probation, keep packets in a list. */
 
956
        g_queue_push_tail (src->packets, buffer);
 
957
        /* remove packets from queue if there are too many */
 
958
        while (g_queue_get_length (src->packets) > RTP_MAX_PROBATION_LEN) {
 
959
          q = g_queue_pop_head (src->packets);
 
960
          gst_buffer_unref (q);
 
961
        }
 
962
        goto done;
 
963
      }
 
964
    } else {
 
965
      GST_DEBUG ("probation: seqnr %d != expected %d", seqnr, expected);
 
966
      src->probation = RTP_DEFAULT_PROBATION;
 
967
      src->stats.max_seq = seqnr;
 
968
      goto done;
 
969
    }
 
970
  } else if (udelta < RTP_MAX_DROPOUT) {
 
971
    /* in order, with permissible gap */
 
972
    if (seqnr < stats->max_seq) {
 
973
      /* sequence number wrapped - count another 64K cycle. */
 
974
      stats->cycles += RTP_SEQ_MOD;
 
975
    }
 
976
    stats->max_seq = seqnr;
 
977
  } else if (udelta <= RTP_SEQ_MOD - RTP_MAX_MISORDER) {
 
978
    /* the sequence number made a very large jump */
 
979
    if (seqnr == stats->bad_seq) {
 
980
      /* two sequential packets -- assume that the other side
 
981
       * restarted without telling us so just re-sync
 
982
       * (i.e., pretend this was the first packet).  */
 
983
      init_seq (src, seqnr);
 
984
    } else {
 
985
      /* unacceptable jump */
 
986
      stats->bad_seq = (seqnr + 1) & (RTP_SEQ_MOD - 1);
 
987
      goto bad_sequence;
 
988
    }
 
989
  } else {
 
990
    /* duplicate or reordered packet, will be filtered by jitterbuffer. */
 
991
    GST_WARNING ("duplicate or reordered packet");
 
992
  }
 
993
 
 
994
  src->stats.octets_received += arrival->payload_len;
 
995
  src->stats.bytes_received += arrival->bytes;
 
996
  src->stats.packets_received++;
 
997
  /* the source that sent the packet must be a sender */
 
998
  src->is_sender = TRUE;
 
999
  src->validated = TRUE;
 
1000
 
 
1001
  GST_LOG ("seq %d, PC: %" G_GUINT64_FORMAT ", OC: %" G_GUINT64_FORMAT,
 
1002
      seqnr, src->stats.packets_received, src->stats.octets_received);
 
1003
 
 
1004
  /* calculate jitter for the stats */
 
1005
  calculate_jitter (src, buffer, arrival);
 
1006
 
 
1007
  /* we're ready to push the RTP packet now */
 
1008
  result = push_packet (src, buffer);
 
1009
 
 
1010
done:
 
1011
  return result;
 
1012
 
 
1013
  /* ERRORS */
 
1014
bad_sequence:
 
1015
  {
 
1016
    GST_WARNING ("unacceptable seqnum received");
 
1017
    return GST_FLOW_OK;
 
1018
  }
 
1019
}
 
1020
 
 
1021
/**
 
1022
 * rtp_source_process_bye:
 
1023
 * @src: an #RTPSource
 
1024
 * @reason: the reason for leaving
 
1025
 *
 
1026
 * Notify @src that a BYE packet has been received. This will make the source
 
1027
 * inactive.
 
1028
 */
 
1029
void
 
1030
rtp_source_process_bye (RTPSource * src, const gchar * reason)
 
1031
{
 
1032
  g_return_if_fail (RTP_IS_SOURCE (src));
 
1033
 
 
1034
  GST_DEBUG ("marking SSRC %08x as BYE, reason: %s", src->ssrc,
 
1035
      GST_STR_NULL (reason));
 
1036
 
 
1037
  /* copy the reason and mark as received_bye */
 
1038
  g_free (src->bye_reason);
 
1039
  src->bye_reason = g_strdup (reason);
 
1040
  src->received_bye = TRUE;
 
1041
}
 
1042
 
 
1043
/**
 
1044
 * rtp_source_send_rtp:
 
1045
 * @src: an #RTPSource
 
1046
 * @buffer: an RTP buffer
 
1047
 * @ntpnstime: the NTP time when this buffer was captured in nanoseconds. This
 
1048
 * is the buffer timestamp converted to NTP time.
 
1049
 *
 
1050
 * Send an RTP @buffer originating from @src. This will make @src a sender.
 
1051
 * This function takes ownership of @buffer and modifies the SSRC in the RTP
 
1052
 * packet to that of @src when needed.
 
1053
 *
 
1054
 * Returns: a #GstFlowReturn.
 
1055
 */
 
1056
GstFlowReturn
 
1057
rtp_source_send_rtp (RTPSource * src, GstBuffer * buffer, guint64 ntpnstime)
 
1058
{
 
1059
  GstFlowReturn result = GST_FLOW_OK;
 
1060
  guint len;
 
1061
  guint32 rtptime;
 
1062
  guint64 ext_rtptime;
 
1063
  guint64 ntp_diff, rtp_diff;
 
1064
  guint64 elapsed;
 
1065
 
 
1066
  g_return_val_if_fail (RTP_IS_SOURCE (src), GST_FLOW_ERROR);
 
1067
  g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
 
1068
 
 
1069
  len = gst_rtp_buffer_get_payload_len (buffer);
 
1070
 
 
1071
  rtp_source_update_caps (src, GST_BUFFER_CAPS (buffer));
 
1072
 
 
1073
  /* we are a sender now */
 
1074
  src->is_sender = TRUE;
 
1075
 
 
1076
  /* update stats for the SR */
 
1077
  src->stats.packets_sent++;
 
1078
  src->stats.octets_sent += len;
 
1079
  src->bytes_sent += len;
 
1080
 
 
1081
  if (src->prev_ntpnstime) {
 
1082
    elapsed = ntpnstime - src->prev_ntpnstime;
 
1083
 
 
1084
    if (elapsed > (G_GINT64_CONSTANT (1) << 31)) {
 
1085
      guint64 rate;
 
1086
 
 
1087
      rate =
 
1088
          gst_util_uint64_scale (src->bytes_sent, elapsed,
 
1089
          (G_GINT64_CONSTANT (1) << 29));
 
1090
 
 
1091
      GST_LOG ("Elapsed %" G_GUINT64_FORMAT ", bytes %" G_GUINT64_FORMAT
 
1092
          ", rate %" G_GUINT64_FORMAT, elapsed, src->bytes_sent, rate);
 
1093
 
 
1094
      if (src->bitrate == 0)
 
1095
        src->bitrate = rate;
 
1096
      else
 
1097
        src->bitrate = ((src->bitrate * 3) + rate) / 4;
 
1098
 
 
1099
      src->prev_ntpnstime = ntpnstime;
 
1100
      src->bytes_sent = 0;
 
1101
    }
 
1102
  } else {
 
1103
    GST_LOG ("Reset bitrate measurement");
 
1104
    src->prev_ntpnstime = ntpnstime;
 
1105
    src->bitrate = 0;
 
1106
  }
 
1107
 
 
1108
  rtptime = gst_rtp_buffer_get_timestamp (buffer);
 
1109
  ext_rtptime = src->last_rtptime;
 
1110
  ext_rtptime = gst_rtp_buffer_ext_timestamp (&ext_rtptime, rtptime);
 
1111
 
 
1112
  GST_LOG ("SSRC %08x, RTP %" G_GUINT64_FORMAT ", NTP %" GST_TIME_FORMAT,
 
1113
      src->ssrc, ext_rtptime, GST_TIME_ARGS (ntpnstime));
 
1114
 
 
1115
  if (ext_rtptime > src->last_rtptime) {
 
1116
    rtp_diff = ext_rtptime - src->last_rtptime;
 
1117
    ntp_diff = ntpnstime - src->last_ntpnstime;
 
1118
 
 
1119
    /* calc the diff so we can detect drift at the sender. This can also be used
 
1120
     * to guestimate the clock rate if the NTP time is locked to the RTP
 
1121
     * timestamps (as is the case when the capture device is providing the clock). */
 
1122
    GST_LOG ("SSRC %08x, diff RTP %" G_GUINT64_FORMAT ", diff NTP %"
 
1123
        GST_TIME_FORMAT, src->ssrc, rtp_diff, GST_TIME_ARGS (ntp_diff));
 
1124
  }
 
1125
 
 
1126
  /* we keep track of the last received RTP timestamp and the corresponding
 
1127
   * NTP timestamp so that we can use this info when constructing SR reports */
 
1128
  src->last_rtptime = ext_rtptime;
 
1129
  src->last_ntpnstime = ntpnstime;
 
1130
 
 
1131
  /* push packet */
 
1132
  if (src->callbacks.push_rtp) {
 
1133
    guint32 ssrc;
 
1134
 
 
1135
    ssrc = gst_rtp_buffer_get_ssrc (buffer);
 
1136
    if (ssrc != src->ssrc) {
 
1137
      /* the SSRC of the packet is not correct, make a writable buffer and
 
1138
       * update the SSRC. This could involve a complete copy of the packet when
 
1139
       * it is not writable. Usually the payloader will use caps negotiation to
 
1140
       * get the correct SSRC from the session manager before pushing anything. */
 
1141
      buffer = gst_buffer_make_writable (buffer);
 
1142
 
 
1143
      GST_WARNING ("updating SSRC from %08x to %08x, fix the payloader", ssrc,
 
1144
          src->ssrc);
 
1145
      gst_rtp_buffer_set_ssrc (buffer, src->ssrc);
 
1146
    }
 
1147
    GST_LOG ("pushing RTP packet %" G_GUINT64_FORMAT, src->stats.packets_sent);
 
1148
    result = src->callbacks.push_rtp (src, buffer, src->user_data);
 
1149
  } else {
 
1150
    GST_WARNING ("no callback installed, dropping packet");
 
1151
    gst_buffer_unref (buffer);
 
1152
  }
 
1153
 
 
1154
  return result;
 
1155
}
 
1156
 
 
1157
/**
 
1158
 * rtp_source_process_sr:
 
1159
 * @src: an #RTPSource
 
1160
 * @time: time of packet arrival
 
1161
 * @ntptime: the NTP time in 32.32 fixed point
 
1162
 * @rtptime: the RTP time
 
1163
 * @packet_count: the packet count
 
1164
 * @octet_count: the octect count
 
1165
 *
 
1166
 * Update the sender report in @src.
 
1167
 */
 
1168
void
 
1169
rtp_source_process_sr (RTPSource * src, GstClockTime time, guint64 ntptime,
 
1170
    guint32 rtptime, guint32 packet_count, guint32 octet_count)
 
1171
{
 
1172
  RTPSenderReport *curr;
 
1173
  gint curridx;
 
1174
 
 
1175
  g_return_if_fail (RTP_IS_SOURCE (src));
 
1176
 
 
1177
  GST_DEBUG ("got SR packet: SSRC %08x, NTP %08x:%08x, RTP %" G_GUINT32_FORMAT
 
1178
      ", PC %" G_GUINT32_FORMAT ", OC %" G_GUINT32_FORMAT, src->ssrc,
 
1179
      (guint32) (ntptime >> 32), (guint32) (ntptime & 0xffffffff), rtptime,
 
1180
      packet_count, octet_count);
 
1181
 
 
1182
  curridx = src->stats.curr_sr ^ 1;
 
1183
  curr = &src->stats.sr[curridx];
 
1184
 
 
1185
  /* this is a sender now */
 
1186
  src->is_sender = TRUE;
 
1187
 
 
1188
  /* update current */
 
1189
  curr->is_valid = TRUE;
 
1190
  curr->ntptime = ntptime;
 
1191
  curr->rtptime = rtptime;
 
1192
  curr->packet_count = packet_count;
 
1193
  curr->octet_count = octet_count;
 
1194
  curr->time = time;
 
1195
 
 
1196
  /* make current */
 
1197
  src->stats.curr_sr = curridx;
 
1198
}
 
1199
 
 
1200
/**
 
1201
 * rtp_source_process_rb:
 
1202
 * @src: an #RTPSource
 
1203
 * @time: the current time in nanoseconds since 1970
 
1204
 * @fractionlost: fraction lost since last SR/RR
 
1205
 * @packetslost: the cumululative number of packets lost
 
1206
 * @exthighestseq: the extended last sequence number received
 
1207
 * @jitter: the interarrival jitter
 
1208
 * @lsr: the last SR packet from this source
 
1209
 * @dlsr: the delay since last SR packet
 
1210
 *
 
1211
 * Update the report block in @src.
 
1212
 */
 
1213
void
 
1214
rtp_source_process_rb (RTPSource * src, GstClockTime time, guint8 fractionlost,
 
1215
    gint32 packetslost, guint32 exthighestseq, guint32 jitter, guint32 lsr,
 
1216
    guint32 dlsr)
 
1217
{
 
1218
  RTPReceiverReport *curr;
 
1219
  gint curridx;
 
1220
  guint32 ntp, A;
 
1221
 
 
1222
  g_return_if_fail (RTP_IS_SOURCE (src));
 
1223
 
 
1224
  GST_DEBUG ("got RB packet: SSRC %08x, FL %2x, PL %d, HS %" G_GUINT32_FORMAT
 
1225
      ", jitter %" G_GUINT32_FORMAT ", LSR %04x:%04x, DLSR %04x:%04x",
 
1226
      src->ssrc, fractionlost, packetslost, exthighestseq, jitter, lsr >> 16,
 
1227
      lsr & 0xffff, dlsr >> 16, dlsr & 0xffff);
 
1228
 
 
1229
  curridx = src->stats.curr_rr ^ 1;
 
1230
  curr = &src->stats.rr[curridx];
 
1231
 
 
1232
  /* update current */
 
1233
  curr->is_valid = TRUE;
 
1234
  curr->fractionlost = fractionlost;
 
1235
  curr->packetslost = packetslost;
 
1236
  curr->exthighestseq = exthighestseq;
 
1237
  curr->jitter = jitter;
 
1238
  curr->lsr = lsr;
 
1239
  curr->dlsr = dlsr;
 
1240
 
 
1241
  /* calculate round trip, round the time up */
 
1242
  ntp = ((gst_rtcp_unix_to_ntp (time) + 0xffff) >> 16) & 0xffffffff;
 
1243
  A = dlsr + lsr;
 
1244
  if (A > 0 && ntp > A)
 
1245
    A = ntp - A;
 
1246
  else
 
1247
    A = 0;
 
1248
  curr->round_trip = A;
 
1249
 
 
1250
  GST_DEBUG ("NTP %04x:%04x, round trip %04x:%04x", ntp >> 16, ntp & 0xffff,
 
1251
      A >> 16, A & 0xffff);
 
1252
 
 
1253
  /* make current */
 
1254
  src->stats.curr_rr = curridx;
 
1255
}
 
1256
 
 
1257
/**
 
1258
 * rtp_source_get_new_sr:
 
1259
 * @src: an #RTPSource
 
1260
 * @ntpnstime: the current time in nanoseconds since 1970
 
1261
 * @ntptime: the NTP time in 32.32 fixed point
 
1262
 * @rtptime: the RTP time corresponding to @ntptime
 
1263
 * @packet_count: the packet count
 
1264
 * @octet_count: the octect count
 
1265
 *
 
1266
 * Get new values to put into a new SR report from this source.
 
1267
 *
 
1268
 * Returns: %TRUE on success.
 
1269
 */
 
1270
gboolean
 
1271
rtp_source_get_new_sr (RTPSource * src, guint64 ntpnstime,
 
1272
    guint64 * ntptime, guint32 * rtptime, guint32 * packet_count,
 
1273
    guint32 * octet_count)
 
1274
{
 
1275
  guint64 t_rtp;
 
1276
  guint64 t_current_ntp;
 
1277
  GstClockTimeDiff diff;
 
1278
 
 
1279
  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
 
1280
 
 
1281
  /* use the sync params to interpolate the date->time member to rtptime. We
 
1282
   * use the last sent timestamp and rtptime as reference points. We assume
 
1283
   * that the slope of the rtptime vs timestamp curve is 1, which is certainly
 
1284
   * sufficient for the frequency at which we report SR and the rate we send
 
1285
   * out RTP packets. */
 
1286
  t_rtp = src->last_rtptime;
 
1287
 
 
1288
  GST_DEBUG ("last_ntpnstime %" GST_TIME_FORMAT ", last_rtptime %"
 
1289
      G_GUINT64_FORMAT, GST_TIME_ARGS (src->last_ntpnstime), t_rtp);
 
1290
 
 
1291
  if (src->clock_rate != -1) {
 
1292
    /* get the diff with the SR time */
 
1293
    diff = GST_CLOCK_DIFF (src->last_ntpnstime, ntpnstime);
 
1294
 
 
1295
    /* now translate the diff to RTP time, handle positive and negative cases.
 
1296
     * If there is no diff, we already set rtptime correctly above. */
 
1297
    if (diff > 0) {
 
1298
      GST_DEBUG ("ntpnstime %" GST_TIME_FORMAT ", diff %" GST_TIME_FORMAT,
 
1299
          GST_TIME_ARGS (ntpnstime), GST_TIME_ARGS (diff));
 
1300
      t_rtp += gst_util_uint64_scale_int (diff, src->clock_rate, GST_SECOND);
 
1301
    } else {
 
1302
      diff = -diff;
 
1303
      GST_DEBUG ("ntpnstime %" GST_TIME_FORMAT ", diff -%" GST_TIME_FORMAT,
 
1304
          GST_TIME_ARGS (ntpnstime), GST_TIME_ARGS (diff));
 
1305
      t_rtp -= gst_util_uint64_scale_int (diff, src->clock_rate, GST_SECOND);
 
1306
    }
 
1307
  } else {
 
1308
    GST_WARNING ("no clock-rate, cannot interpolate rtp time");
 
1309
  }
 
1310
 
 
1311
  /* convert the NTP time in nanoseconds to 32.32 fixed point */
 
1312
  t_current_ntp = gst_util_uint64_scale (ntpnstime, (1LL << 32), GST_SECOND);
 
1313
 
 
1314
  GST_DEBUG ("NTP %08x:%08x, RTP %" G_GUINT32_FORMAT,
 
1315
      (guint32) (t_current_ntp >> 32), (guint32) (t_current_ntp & 0xffffffff),
 
1316
      (guint32) t_rtp);
 
1317
 
 
1318
  if (ntptime)
 
1319
    *ntptime = t_current_ntp;
 
1320
  if (rtptime)
 
1321
    *rtptime = t_rtp;
 
1322
  if (packet_count)
 
1323
    *packet_count = src->stats.packets_sent;
 
1324
  if (octet_count)
 
1325
    *octet_count = src->stats.octets_sent;
 
1326
 
 
1327
  return TRUE;
 
1328
}
 
1329
 
 
1330
/**
 
1331
 * rtp_source_get_new_rb:
 
1332
 * @src: an #RTPSource
 
1333
 * @time: the current time of the system clock
 
1334
 * @fractionlost: fraction lost since last SR/RR
 
1335
 * @packetslost: the cumululative number of packets lost
 
1336
 * @exthighestseq: the extended last sequence number received
 
1337
 * @jitter: the interarrival jitter
 
1338
 * @lsr: the last SR packet from this source
 
1339
 * @dlsr: the delay since last SR packet
 
1340
 *
 
1341
 * Get new values to put into a new report block from this source.
 
1342
 *
 
1343
 * Returns: %TRUE on success.
 
1344
 */
 
1345
gboolean
 
1346
rtp_source_get_new_rb (RTPSource * src, GstClockTime time,
 
1347
    guint8 * fractionlost, gint32 * packetslost, guint32 * exthighestseq,
 
1348
    guint32 * jitter, guint32 * lsr, guint32 * dlsr)
 
1349
{
 
1350
  RTPSourceStats *stats;
 
1351
  guint64 extended_max, expected;
 
1352
  guint64 expected_interval, received_interval, ntptime;
 
1353
  gint64 lost, lost_interval;
 
1354
  guint32 fraction, LSR, DLSR;
 
1355
  GstClockTime sr_time;
 
1356
 
 
1357
  stats = &src->stats;
 
1358
 
 
1359
  extended_max = stats->cycles + stats->max_seq;
 
1360
  expected = extended_max - stats->base_seq + 1;
 
1361
 
 
1362
  GST_DEBUG ("ext_max %" G_GUINT64_FORMAT ", expected %" G_GUINT64_FORMAT
 
1363
      ", received %" G_GUINT64_FORMAT ", base_seq %" G_GUINT32_FORMAT,
 
1364
      extended_max, expected, stats->packets_received, stats->base_seq);
 
1365
 
 
1366
  lost = expected - stats->packets_received;
 
1367
  lost = CLAMP (lost, -0x800000, 0x7fffff);
 
1368
 
 
1369
  expected_interval = expected - stats->prev_expected;
 
1370
  stats->prev_expected = expected;
 
1371
  received_interval = stats->packets_received - stats->prev_received;
 
1372
  stats->prev_received = stats->packets_received;
 
1373
 
 
1374
  lost_interval = expected_interval - received_interval;
 
1375
 
 
1376
  if (expected_interval == 0 || lost_interval <= 0)
 
1377
    fraction = 0;
 
1378
  else
 
1379
    fraction = (lost_interval << 8) / expected_interval;
 
1380
 
 
1381
  GST_DEBUG ("add RR for SSRC %08x", src->ssrc);
 
1382
  /* we scaled the jitter up for additional precision */
 
1383
  GST_DEBUG ("fraction %" G_GUINT32_FORMAT ", lost %" G_GINT64_FORMAT
 
1384
      ", extseq %" G_GUINT64_FORMAT ", jitter %d", fraction, lost,
 
1385
      extended_max, stats->jitter >> 4);
 
1386
 
 
1387
  if (rtp_source_get_last_sr (src, &sr_time, &ntptime, NULL, NULL, NULL)) {
 
1388
    GstClockTime diff;
 
1389
 
 
1390
    /* LSR is middle 32 bits of the last ntptime */
 
1391
    LSR = (ntptime >> 16) & 0xffffffff;
 
1392
    diff = time - sr_time;
 
1393
    GST_DEBUG ("last SR time diff %" GST_TIME_FORMAT, GST_TIME_ARGS (diff));
 
1394
    /* DLSR, delay since last SR is expressed in 1/65536 second units */
 
1395
    DLSR = gst_util_uint64_scale_int (diff, 65536, GST_SECOND);
 
1396
  } else {
 
1397
    /* No valid SR received, LSR/DLSR are set to 0 then */
 
1398
    GST_DEBUG ("no valid SR received");
 
1399
    LSR = 0;
 
1400
    DLSR = 0;
 
1401
  }
 
1402
  GST_DEBUG ("LSR %04x:%04x, DLSR %04x:%04x", LSR >> 16, LSR & 0xffff,
 
1403
      DLSR >> 16, DLSR & 0xffff);
 
1404
 
 
1405
  if (fractionlost)
 
1406
    *fractionlost = fraction;
 
1407
  if (packetslost)
 
1408
    *packetslost = lost;
 
1409
  if (exthighestseq)
 
1410
    *exthighestseq = extended_max;
 
1411
  if (jitter)
 
1412
    *jitter = stats->jitter >> 4;
 
1413
  if (lsr)
 
1414
    *lsr = LSR;
 
1415
  if (dlsr)
 
1416
    *dlsr = DLSR;
 
1417
 
 
1418
  return TRUE;
 
1419
}
 
1420
 
 
1421
/**
 
1422
 * rtp_source_get_last_sr:
 
1423
 * @src: an #RTPSource
 
1424
 * @time: time of packet arrival
 
1425
 * @ntptime: the NTP time in 32.32 fixed point
 
1426
 * @rtptime: the RTP time
 
1427
 * @packet_count: the packet count
 
1428
 * @octet_count: the octect count
 
1429
 *
 
1430
 * Get the values of the last sender report as set with rtp_source_process_sr().
 
1431
 *
 
1432
 * Returns: %TRUE if there was a valid SR report.
 
1433
 */
 
1434
gboolean
 
1435
rtp_source_get_last_sr (RTPSource * src, GstClockTime * time, guint64 * ntptime,
 
1436
    guint32 * rtptime, guint32 * packet_count, guint32 * octet_count)
 
1437
{
 
1438
  RTPSenderReport *curr;
 
1439
 
 
1440
  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
 
1441
 
 
1442
  curr = &src->stats.sr[src->stats.curr_sr];
 
1443
  if (!curr->is_valid)
 
1444
    return FALSE;
 
1445
 
 
1446
  if (ntptime)
 
1447
    *ntptime = curr->ntptime;
 
1448
  if (rtptime)
 
1449
    *rtptime = curr->rtptime;
 
1450
  if (packet_count)
 
1451
    *packet_count = curr->packet_count;
 
1452
  if (octet_count)
 
1453
    *octet_count = curr->octet_count;
 
1454
  if (time)
 
1455
    *time = curr->time;
 
1456
 
 
1457
  return TRUE;
 
1458
}
 
1459
 
 
1460
/**
 
1461
 * rtp_source_get_last_rb:
 
1462
 * @src: an #RTPSource
 
1463
 * @fractionlost: fraction lost since last SR/RR
 
1464
 * @packetslost: the cumululative number of packets lost
 
1465
 * @exthighestseq: the extended last sequence number received
 
1466
 * @jitter: the interarrival jitter
 
1467
 * @lsr: the last SR packet from this source
 
1468
 * @dlsr: the delay since last SR packet
 
1469
 * @round_trip: the round trip time
 
1470
 *
 
1471
 * Get the values of the last RB report set with rtp_source_process_rb().
 
1472
 *
 
1473
 * Returns: %TRUE if there was a valid SB report.
 
1474
 */
 
1475
gboolean
 
1476
rtp_source_get_last_rb (RTPSource * src, guint8 * fractionlost,
 
1477
    gint32 * packetslost, guint32 * exthighestseq, guint32 * jitter,
 
1478
    guint32 * lsr, guint32 * dlsr, guint32 * round_trip)
 
1479
{
 
1480
  RTPReceiverReport *curr;
 
1481
 
 
1482
  g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
 
1483
 
 
1484
  curr = &src->stats.rr[src->stats.curr_rr];
 
1485
  if (!curr->is_valid)
 
1486
    return FALSE;
 
1487
 
 
1488
  if (fractionlost)
 
1489
    *fractionlost = curr->fractionlost;
 
1490
  if (packetslost)
 
1491
    *packetslost = curr->packetslost;
 
1492
  if (exthighestseq)
 
1493
    *exthighestseq = curr->exthighestseq;
 
1494
  if (jitter)
 
1495
    *jitter = curr->jitter;
 
1496
  if (lsr)
 
1497
    *lsr = curr->lsr;
 
1498
  if (dlsr)
 
1499
    *dlsr = curr->dlsr;
 
1500
  if (round_trip)
 
1501
    *round_trip = curr->round_trip;
 
1502
 
 
1503
  return TRUE;
 
1504
}