~ubuntu-branches/ubuntu/quantal/gst-plugins-bad-multiverse0.10/quantal

« back to all changes in this revision

Viewing changes to gst/rtpmanager/gstrtpbin.c

  • Committer: Bazaar Package Importer
  • Author(s): Onkar Shinde
  • Date: 2009-12-07 08:54:28 UTC
  • mfrom: (1.1.15 upstream)
  • Revision ID: james.westby@ubuntu.com-20091207085428-ml6aaukf0p2ph34d
Tags: 0.10.17-0ubuntu1
* New upstream release.
* Add myself to maintainer.
* Fix misc lintian warnings.

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
 
 
20
 
/**
21
 
 * SECTION:element-gstrtpbin
22
 
 * @see_also: gstrtpjitterbuffer, gstrtpsession, gstrtpptdemux, gstrtpssrcdemux
23
 
 *
24
 
 * RTP bin combines the functions of #GstRtpSession, #GstRtpsSrcDemux,
25
 
 * #GstRtpJitterBuffer and #GstRtpPtDemux in one element. It allows for multiple
26
 
 * RTP sessions that will be synchronized together using RTCP SR packets.
27
 
 * 
28
 
 * #GstRtpBin is configured with a number of request pads that define the
29
 
 * functionality that is activated, similar to the #GstRtpSession element.
30
 
 * 
31
 
 * To use #GstRtpBin as an RTP receiver, request a recv_rtp_sink_%%d pad. The session
32
 
 * number must be specified in the pad name. 
33
 
 * Data received on the recv_rtp_sink_%%d pad will be processed in the gstrtpsession
34
 
 * manager and after being validated forwarded on #GstRtpsSrcDemux element. Each
35
 
 * RTP stream is demuxed based on the SSRC and send to a #GstRtpJitterBuffer. After
36
 
 * the packets are released from the jitterbuffer, they will be forwarded to a
37
 
 * #GstRtpsSrcDemux element. The #GstRtpsSrcDemux element will demux the packets based
38
 
 * on the payload type and will create a unique pad recv_rtp_src_%%d_%%d_%%d on
39
 
 * gstrtpbin with the session number, SSRC and payload type respectively as the pad
40
 
 * name.
41
 
 * 
42
 
 * To also use #GstRtpBin as an RTCP receiver, request a recv_rtcp_sink_%%d pad. The
43
 
 * session number must be specified in the pad name.
44
 
 * 
45
 
 * If you want the session manager to generate and send RTCP packets, request
46
 
 * the send_rtcp_src_%%d pad with the session number in the pad name. Packet pushed
47
 
 * on this pad contain SR/RR RTCP reports that should be sent to all participants
48
 
 * in the session.
49
 
 * 
50
 
 * To use #GstRtpBin as a sender, request a send_rtp_sink_%%d pad, which will
51
 
 * automatically create a send_rtp_src_%%d pad. If the session number is not provided,
52
 
 * the pad from the lowest available session will be returned. The session manager will modify the
53
 
 * SSRC in the RTP packets to its own SSRC and wil forward the packets on the
54
 
 * send_rtp_src_%%d pad after updating its internal state.
55
 
 * 
56
 
 * The session manager needs the clock-rate of the payload types it is handling
57
 
 * and will signal the #GstRtpSession::request-pt-map signal when it needs such a
58
 
 * mapping. One can clear the cached values with the #GstRtpSession::clear-pt-map
59
 
 * signal.
60
 
 * 
61
 
 * <refsect2>
62
 
 * <title>Example pipelines</title>
63
 
 * |[
64
 
 * gst-launch udpsrc port=5000 caps="application/x-rtp, ..." ! .recv_rtp_sink_0 \
65
 
 *     gstrtpbin ! rtptheoradepay ! theoradec ! xvimagesink
66
 
 * ]| Receive RTP data from port 5000 and send to the session 0 in gstrtpbin.
67
 
 * |[
68
 
 * gst-launch gstrtpbin name=rtpbin \
69
 
 *         v4l2src ! ffmpegcolorspace ! ffenc_h263 ! rtph263ppay ! rtpbin.send_rtp_sink_0 \
70
 
 *                   rtpbin.send_rtp_src_0 ! udpsink port=5000                            \
71
 
 *                   rtpbin.send_rtcp_src_0 ! udpsink port=5001 sync=false async=false    \
72
 
 *                   udpsrc port=5005 ! rtpbin.recv_rtcp_sink_0                           \
73
 
 *         audiotestsrc ! amrnbenc ! rtpamrpay ! rtpbin.send_rtp_sink_1                   \
74
 
 *                   rtpbin.send_rtp_src_1 ! udpsink port=5002                            \
75
 
 *                   rtpbin.send_rtcp_src_1 ! udpsink port=5003 sync=false async=false    \
76
 
 *                   udpsrc port=5007 ! rtpbin.recv_rtcp_sink_1
77
 
 * ]| Encode and payload H263 video captured from a v4l2src. Encode and payload AMR
78
 
 * audio generated from audiotestsrc. The video is sent to session 0 in rtpbin
79
 
 * and the audio is sent to session 1. Video packets are sent on UDP port 5000
80
 
 * and audio packets on port 5002. The video RTCP packets for session 0 are sent
81
 
 * on port 5001 and the audio RTCP packets for session 0 are sent on port 5003.
82
 
 * RTCP packets for session 0 are received on port 5005 and RTCP for session 1
83
 
 * is received on port 5007. Since RTCP packets from the sender should be sent
84
 
 * as soon as possible and do not participate in preroll, sync=false and 
85
 
 * async=false is configured on udpsink
86
 
 * |[
87
 
 * gst-launch -v gstrtpbin name=rtpbin                                          \
88
 
 *     udpsrc caps="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H263-1998" \
89
 
 *             port=5000 ! rtpbin.recv_rtp_sink_0                                \
90
 
 *         rtpbin. ! rtph263pdepay ! ffdec_h263 ! xvimagesink                    \
91
 
 *      udpsrc port=5001 ! rtpbin.recv_rtcp_sink_0                               \
92
 
 *      rtpbin.send_rtcp_src_0 ! udpsink port=5005 sync=false async=false        \
93
 
 *     udpsrc caps="application/x-rtp,media=(string)audio,clock-rate=(int)8000,encoding-name=(string)AMR,encoding-params=(string)1,octet-align=(string)1" \
94
 
 *             port=5002 ! rtpbin.recv_rtp_sink_1                                \
95
 
 *         rtpbin. ! rtpamrdepay ! amrnbdec ! alsasink                           \
96
 
 *      udpsrc port=5003 ! rtpbin.recv_rtcp_sink_1                               \
97
 
 *      rtpbin.send_rtcp_src_1 ! udpsink port=5007 sync=false async=false
98
 
 * ]| Receive H263 on port 5000, send it through rtpbin in session 0, depayload,
99
 
 * decode and display the video.
100
 
 * Receive AMR on port 5002, send it through rtpbin in session 1, depayload,
101
 
 * decode and play the audio.
102
 
 * Receive server RTCP packets for session 0 on port 5001 and RTCP packets for
103
 
 * session 1 on port 5003. These packets will be used for session management and
104
 
 * synchronisation.
105
 
 * Send RTCP reports for session 0 on port 5005 and RTCP reports for session 1
106
 
 * on port 5007.
107
 
 * </refsect2>
108
 
 *
109
 
 * Last reviewed on 2007-08-30 (0.10.6)
110
 
 */
111
 
 
112
 
#ifdef HAVE_CONFIG_H
113
 
#include "config.h"
114
 
#endif
115
 
#include <string.h>
116
 
 
117
 
#include <gst/rtp/gstrtpbuffer.h>
118
 
#include <gst/rtp/gstrtcpbuffer.h>
119
 
 
120
 
#include "gstrtpbin-marshal.h"
121
 
#include "gstrtpbin.h"
122
 
#include "rtpsession.h"
123
 
#include "gstrtpsession.h"
124
 
#include "gstrtpjitterbuffer.h"
125
 
 
126
 
GST_DEBUG_CATEGORY_STATIC (gst_rtp_bin_debug);
127
 
#define GST_CAT_DEFAULT gst_rtp_bin_debug
128
 
 
129
 
/* elementfactory information */
130
 
static const GstElementDetails rtpbin_details = GST_ELEMENT_DETAILS ("RTP Bin",
131
 
    "Filter/Network/RTP",
132
 
    "Implement an RTP bin",
133
 
    "Wim Taymans <wim.taymans@gmail.com>");
134
 
 
135
 
/* sink pads */
136
 
static GstStaticPadTemplate rtpbin_recv_rtp_sink_template =
137
 
GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%d",
138
 
    GST_PAD_SINK,
139
 
    GST_PAD_REQUEST,
140
 
    GST_STATIC_CAPS ("application/x-rtp")
141
 
    );
142
 
 
143
 
static GstStaticPadTemplate rtpbin_recv_rtcp_sink_template =
144
 
GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%d",
145
 
    GST_PAD_SINK,
146
 
    GST_PAD_REQUEST,
147
 
    GST_STATIC_CAPS ("application/x-rtcp")
148
 
    );
149
 
 
150
 
static GstStaticPadTemplate rtpbin_send_rtp_sink_template =
151
 
GST_STATIC_PAD_TEMPLATE ("send_rtp_sink_%d",
152
 
    GST_PAD_SINK,
153
 
    GST_PAD_REQUEST,
154
 
    GST_STATIC_CAPS ("application/x-rtp")
155
 
    );
156
 
 
157
 
/* src pads */
158
 
static GstStaticPadTemplate rtpbin_recv_rtp_src_template =
159
 
GST_STATIC_PAD_TEMPLATE ("recv_rtp_src_%d_%d_%d",
160
 
    GST_PAD_SRC,
161
 
    GST_PAD_SOMETIMES,
162
 
    GST_STATIC_CAPS ("application/x-rtp")
163
 
    );
164
 
 
165
 
static GstStaticPadTemplate rtpbin_send_rtcp_src_template =
166
 
GST_STATIC_PAD_TEMPLATE ("send_rtcp_src_%d",
167
 
    GST_PAD_SRC,
168
 
    GST_PAD_REQUEST,
169
 
    GST_STATIC_CAPS ("application/x-rtcp")
170
 
    );
171
 
 
172
 
static GstStaticPadTemplate rtpbin_send_rtp_src_template =
173
 
GST_STATIC_PAD_TEMPLATE ("send_rtp_src_%d",
174
 
    GST_PAD_SRC,
175
 
    GST_PAD_SOMETIMES,
176
 
    GST_STATIC_CAPS ("application/x-rtp")
177
 
    );
178
 
 
179
 
#define GST_RTP_BIN_GET_PRIVATE(obj)  \
180
 
   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTP_BIN, GstRtpBinPrivate))
181
 
 
182
 
#define GST_RTP_BIN_LOCK(bin)   g_mutex_lock ((bin)->priv->bin_lock)
183
 
#define GST_RTP_BIN_UNLOCK(bin) g_mutex_unlock ((bin)->priv->bin_lock)
184
 
 
185
 
/* lock to protect dynamic callbacks, like pad-added and new ssrc. */
186
 
#define GST_RTP_BIN_DYN_LOCK(bin)    g_mutex_lock ((bin)->priv->dyn_lock)
187
 
#define GST_RTP_BIN_DYN_UNLOCK(bin)  g_mutex_unlock ((bin)->priv->dyn_lock)
188
 
 
189
 
/* lock for shutdown */
190
 
#define GST_RTP_BIN_SHUTDOWN_LOCK(bin,label)     \
191
 
G_STMT_START {                                   \
192
 
  if (g_atomic_int_get (&bin->priv->shutdown))   \
193
 
    goto label;                                  \
194
 
  GST_RTP_BIN_DYN_LOCK (bin);                    \
195
 
  if (g_atomic_int_get (&bin->priv->shutdown)) { \
196
 
    GST_RTP_BIN_DYN_UNLOCK (bin);                \
197
 
    goto label;                                  \
198
 
  }                                              \
199
 
} G_STMT_END
200
 
 
201
 
/* unlock for shutdown */
202
 
#define GST_RTP_BIN_SHUTDOWN_UNLOCK(bin)         \
203
 
  GST_RTP_BIN_DYN_UNLOCK (bin);                  \
204
 
 
205
 
struct _GstRtpBinPrivate
206
 
{
207
 
  GMutex *bin_lock;
208
 
 
209
 
  /* lock protecting dynamic adding/removing */
210
 
  GMutex *dyn_lock;
211
 
 
212
 
  /* the time when we went to playing */
213
 
  GstClockTime ntp_ns_base;
214
 
 
215
 
  /* if we are shutting down or not */
216
 
  gint shutdown;
217
 
};
218
 
 
219
 
/* signals and args */
220
 
enum
221
 
{
222
 
  SIGNAL_REQUEST_PT_MAP,
223
 
  SIGNAL_CLEAR_PT_MAP,
224
 
  SIGNAL_RESET_SYNC,
225
 
  SIGNAL_GET_INTERNAL_SESSION,
226
 
 
227
 
  SIGNAL_ON_NEW_SSRC,
228
 
  SIGNAL_ON_SSRC_COLLISION,
229
 
  SIGNAL_ON_SSRC_VALIDATED,
230
 
  SIGNAL_ON_SSRC_ACTIVE,
231
 
  SIGNAL_ON_SSRC_SDES,
232
 
  SIGNAL_ON_BYE_SSRC,
233
 
  SIGNAL_ON_BYE_TIMEOUT,
234
 
  SIGNAL_ON_TIMEOUT,
235
 
  SIGNAL_ON_SENDER_TIMEOUT,
236
 
  SIGNAL_ON_NPT_STOP,
237
 
  LAST_SIGNAL
238
 
};
239
 
 
240
 
#define DEFAULT_LATENCY_MS           200
241
 
#define DEFAULT_SDES_CNAME           NULL
242
 
#define DEFAULT_SDES_NAME            NULL
243
 
#define DEFAULT_SDES_EMAIL           NULL
244
 
#define DEFAULT_SDES_PHONE           NULL
245
 
#define DEFAULT_SDES_LOCATION        NULL
246
 
#define DEFAULT_SDES_TOOL            NULL
247
 
#define DEFAULT_SDES_NOTE            NULL
248
 
#define DEFAULT_DO_LOST              FALSE
249
 
 
250
 
enum
251
 
{
252
 
  PROP_0,
253
 
  PROP_LATENCY,
254
 
  PROP_SDES_CNAME,
255
 
  PROP_SDES_NAME,
256
 
  PROP_SDES_EMAIL,
257
 
  PROP_SDES_PHONE,
258
 
  PROP_SDES_LOCATION,
259
 
  PROP_SDES_TOOL,
260
 
  PROP_SDES_NOTE,
261
 
  PROP_DO_LOST,
262
 
  PROP_LAST
263
 
};
264
 
 
265
 
/* helper objects */
266
 
typedef struct _GstRtpBinSession GstRtpBinSession;
267
 
typedef struct _GstRtpBinStream GstRtpBinStream;
268
 
typedef struct _GstRtpBinClient GstRtpBinClient;
269
 
 
270
 
static guint gst_rtp_bin_signals[LAST_SIGNAL] = { 0 };
271
 
 
272
 
static GstCaps *pt_map_requested (GstElement * element, guint pt,
273
 
    GstRtpBinSession * session);
274
 
static const gchar *sdes_type_to_name (GstRTCPSDESType type);
275
 
static void gst_rtp_bin_set_sdes_string (GstRtpBin * bin,
276
 
    GstRTCPSDESType type, const gchar * data);
277
 
 
278
 
static void free_stream (GstRtpBinStream * stream);
279
 
 
280
 
/* Manages the RTP stream for one SSRC.
281
 
 *
282
 
 * We pipe the stream (comming from the SSRC demuxer) into a jitterbuffer.
283
 
 * If we see an SDES RTCP packet that links multiple SSRCs together based on a
284
 
 * common CNAME, we create a GstRtpBinClient structure to group the SSRCs
285
 
 * together (see below).
286
 
 */
287
 
struct _GstRtpBinStream
288
 
{
289
 
  /* the SSRC of this stream */
290
 
  guint32 ssrc;
291
 
 
292
 
  /* parent bin */
293
 
  GstRtpBin *bin;
294
 
 
295
 
  /* the session this SSRC belongs to */
296
 
  GstRtpBinSession *session;
297
 
 
298
 
  /* the jitterbuffer of the SSRC */
299
 
  GstElement *buffer;
300
 
  gulong buffer_handlesync_sig;
301
 
  gulong buffer_ptreq_sig;
302
 
  gulong buffer_ntpstop_sig;
303
 
 
304
 
  /* the PT demuxer of the SSRC */
305
 
  GstElement *demux;
306
 
  gulong demux_newpad_sig;
307
 
  gulong demux_ptreq_sig;
308
 
  gulong demux_pt_change_sig;
309
 
  /* ghostpads from the ptdemuxer */
310
 
  GSList *pads;
311
 
 
312
 
  /* if we have calculated a valid unix_delta for this stream */
313
 
  gboolean have_sync;
314
 
  /* mapping to local RTP and NTP time */
315
 
  gint64 unix_delta;
316
 
};
317
 
 
318
 
#define GST_RTP_SESSION_LOCK(sess)   g_mutex_lock ((sess)->lock)
319
 
#define GST_RTP_SESSION_UNLOCK(sess) g_mutex_unlock ((sess)->lock)
320
 
 
321
 
/* Manages the receiving end of the packets.
322
 
 *
323
 
 * There is one such structure for each RTP session (audio/video/...).
324
 
 * We get the RTP/RTCP packets and stuff them into the session manager. From
325
 
 * there they are pushed into an SSRC demuxer that splits the stream based on
326
 
 * SSRC. Each of the SSRC streams go into their own jitterbuffer (managed with
327
 
 * the GstRtpBinStream above).
328
 
 */
329
 
struct _GstRtpBinSession
330
 
{
331
 
  /* session id */
332
 
  gint id;
333
 
  /* the parent bin */
334
 
  GstRtpBin *bin;
335
 
  /* the session element */
336
 
  GstElement *session;
337
 
  /* the SSRC demuxer */
338
 
  GstElement *demux;
339
 
  gulong demux_newpad_sig;
340
 
  gulong demux_padremoved_sig;
341
 
 
342
 
  GMutex *lock;
343
 
 
344
 
  /* list of GstRtpBinStream */
345
 
  GSList *streams;
346
 
 
347
 
  /* mapping of payload type to caps */
348
 
  GHashTable *ptmap;
349
 
 
350
 
  /* the pads of the session */
351
 
  GstPad *recv_rtp_sink;
352
 
  GstPad *recv_rtp_sink_ghost;
353
 
  GstPad *recv_rtp_src;
354
 
  GstPad *recv_rtcp_sink;
355
 
  GstPad *recv_rtcp_sink_ghost;
356
 
  GstPad *sync_src;
357
 
  GstPad *send_rtp_sink;
358
 
  GstPad *send_rtp_sink_ghost;
359
 
  GstPad *send_rtp_src;
360
 
  GstPad *send_rtp_src_ghost;
361
 
  GstPad *send_rtcp_src;
362
 
  GstPad *send_rtcp_src_ghost;
363
 
};
364
 
 
365
 
/* Manages the RTP streams that come from one client and should therefore be
366
 
 * synchronized.
367
 
 */
368
 
struct _GstRtpBinClient
369
 
{
370
 
  /* the common CNAME for the streams */
371
 
  gchar *cname;
372
 
  guint cname_len;
373
 
 
374
 
  /* the streams */
375
 
  guint nstreams;
376
 
  GSList *streams;
377
 
};
378
 
 
379
 
/* find a session with the given id. Must be called with RTP_BIN_LOCK */
380
 
static GstRtpBinSession *
381
 
find_session_by_id (GstRtpBin * rtpbin, gint id)
382
 
{
383
 
  GSList *walk;
384
 
 
385
 
  for (walk = rtpbin->sessions; walk; walk = g_slist_next (walk)) {
386
 
    GstRtpBinSession *sess = (GstRtpBinSession *) walk->data;
387
 
 
388
 
    if (sess->id == id)
389
 
      return sess;
390
 
  }
391
 
  return NULL;
392
 
}
393
 
 
394
 
/* find a session with the given request pad. Must be called with RTP_BIN_LOCK */
395
 
static GstRtpBinSession *
396
 
find_session_by_pad (GstRtpBin * rtpbin, GstPad * pad)
397
 
{
398
 
  GSList *walk;
399
 
 
400
 
  for (walk = rtpbin->sessions; walk; walk = g_slist_next (walk)) {
401
 
    GstRtpBinSession *sess = (GstRtpBinSession *) walk->data;
402
 
 
403
 
    if ((sess->recv_rtp_sink_ghost == pad) ||
404
 
        (sess->recv_rtcp_sink_ghost == pad) ||
405
 
        (sess->send_rtp_sink_ghost == pad)
406
 
        || (sess->send_rtcp_src_ghost == pad))
407
 
      return sess;
408
 
  }
409
 
  return NULL;
410
 
}
411
 
 
412
 
static void
413
 
on_new_ssrc (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
414
 
{
415
 
  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_NEW_SSRC], 0,
416
 
      sess->id, ssrc);
417
 
}
418
 
 
419
 
static void
420
 
on_ssrc_collision (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
421
 
{
422
 
  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SSRC_COLLISION], 0,
423
 
      sess->id, ssrc);
424
 
}
425
 
 
426
 
static void
427
 
on_ssrc_validated (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
428
 
{
429
 
  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SSRC_VALIDATED], 0,
430
 
      sess->id, ssrc);
431
 
}
432
 
 
433
 
static void
434
 
on_ssrc_active (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
435
 
{
436
 
  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SSRC_ACTIVE], 0,
437
 
      sess->id, ssrc);
438
 
}
439
 
 
440
 
static void
441
 
on_ssrc_sdes (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
442
 
{
443
 
  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SSRC_SDES], 0,
444
 
      sess->id, ssrc);
445
 
}
446
 
 
447
 
static void
448
 
on_bye_ssrc (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
449
 
{
450
 
  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_BYE_SSRC], 0,
451
 
      sess->id, ssrc);
452
 
}
453
 
 
454
 
static void
455
 
on_bye_timeout (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
456
 
{
457
 
  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_BYE_TIMEOUT], 0,
458
 
      sess->id, ssrc);
459
 
}
460
 
 
461
 
static void
462
 
on_timeout (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
463
 
{
464
 
  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_TIMEOUT], 0,
465
 
      sess->id, ssrc);
466
 
}
467
 
 
468
 
static void
469
 
on_sender_timeout (GstElement * session, guint32 ssrc, GstRtpBinSession * sess)
470
 
{
471
 
  g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SENDER_TIMEOUT], 0,
472
 
      sess->id, ssrc);
473
 
}
474
 
 
475
 
static void
476
 
on_npt_stop (GstElement * jbuf, GstRtpBinStream * stream)
477
 
{
478
 
  g_signal_emit (stream->bin, gst_rtp_bin_signals[SIGNAL_ON_NPT_STOP], 0,
479
 
      stream->session->id, stream->ssrc);
480
 
}
481
 
 
482
 
/* must be called with the SESSION lock */
483
 
static GstRtpBinStream *
484
 
find_stream_by_ssrc (GstRtpBinSession * session, guint32 ssrc)
485
 
{
486
 
  GSList *walk;
487
 
 
488
 
  for (walk = session->streams; walk; walk = g_slist_next (walk)) {
489
 
    GstRtpBinStream *stream = (GstRtpBinStream *) walk->data;
490
 
 
491
 
    if (stream->ssrc == ssrc)
492
 
      return stream;
493
 
  }
494
 
  return NULL;
495
 
}
496
 
 
497
 
static void
498
 
ssrc_demux_pad_removed (GstElement * element, guint ssrc, GstPad * pad,
499
 
    GstRtpBinSession * session)
500
 
{
501
 
  GstRtpBinStream *stream = NULL;
502
 
 
503
 
  GST_RTP_SESSION_LOCK (session);
504
 
  if ((stream = find_stream_by_ssrc (session, ssrc)))
505
 
    session->streams = g_slist_remove (session->streams, stream);
506
 
  GST_RTP_SESSION_UNLOCK (session);
507
 
 
508
 
  if (stream)
509
 
    free_stream (stream);
510
 
}
511
 
 
512
 
/* create a session with the given id.  Must be called with RTP_BIN_LOCK */
513
 
static GstRtpBinSession *
514
 
create_session (GstRtpBin * rtpbin, gint id)
515
 
{
516
 
  GstRtpBinSession *sess;
517
 
  GstElement *session, *demux;
518
 
  gint i;
519
 
  GstState target;
520
 
 
521
 
  if (!(session = gst_element_factory_make ("gstrtpsession", NULL)))
522
 
    goto no_session;
523
 
 
524
 
  if (!(demux = gst_element_factory_make ("gstrtpssrcdemux", NULL)))
525
 
    goto no_demux;
526
 
 
527
 
  sess = g_new0 (GstRtpBinSession, 1);
528
 
  sess->lock = g_mutex_new ();
529
 
  sess->id = id;
530
 
  sess->bin = rtpbin;
531
 
  sess->session = session;
532
 
  sess->demux = demux;
533
 
  sess->ptmap = g_hash_table_new_full (NULL, NULL, NULL,
534
 
      (GDestroyNotify) gst_caps_unref);
535
 
  rtpbin->sessions = g_slist_prepend (rtpbin->sessions, sess);
536
 
 
537
 
  /* set NTP base or new session */
538
 
  g_object_set (session, "ntp-ns-base", rtpbin->priv->ntp_ns_base, NULL);
539
 
  /* configure SDES items */
540
 
  GST_OBJECT_LOCK (rtpbin);
541
 
  for (i = GST_RTCP_SDES_CNAME; i < GST_RTCP_SDES_PRIV; i++) {
542
 
    g_object_set (session, sdes_type_to_name (i), rtpbin->sdes[i], NULL);
543
 
  }
544
 
  GST_OBJECT_UNLOCK (rtpbin);
545
 
 
546
 
  /* provide clock_rate to the session manager when needed */
547
 
  g_signal_connect (session, "request-pt-map",
548
 
      (GCallback) pt_map_requested, sess);
549
 
 
550
 
  g_signal_connect (sess->session, "on-new-ssrc",
551
 
      (GCallback) on_new_ssrc, sess);
552
 
  g_signal_connect (sess->session, "on-ssrc-collision",
553
 
      (GCallback) on_ssrc_collision, sess);
554
 
  g_signal_connect (sess->session, "on-ssrc-validated",
555
 
      (GCallback) on_ssrc_validated, sess);
556
 
  g_signal_connect (sess->session, "on-ssrc-active",
557
 
      (GCallback) on_ssrc_active, sess);
558
 
  g_signal_connect (sess->session, "on-ssrc-sdes",
559
 
      (GCallback) on_ssrc_sdes, sess);
560
 
  g_signal_connect (sess->session, "on-bye-ssrc",
561
 
      (GCallback) on_bye_ssrc, sess);
562
 
  g_signal_connect (sess->session, "on-bye-timeout",
563
 
      (GCallback) on_bye_timeout, sess);
564
 
  g_signal_connect (sess->session, "on-timeout", (GCallback) on_timeout, sess);
565
 
  g_signal_connect (sess->session, "on-sender-timeout",
566
 
      (GCallback) on_sender_timeout, sess);
567
 
 
568
 
  gst_bin_add (GST_BIN_CAST (rtpbin), session);
569
 
  gst_bin_add (GST_BIN_CAST (rtpbin), demux);
570
 
 
571
 
  GST_OBJECT_LOCK (rtpbin);
572
 
  target = GST_STATE_TARGET (rtpbin);
573
 
  GST_OBJECT_UNLOCK (rtpbin);
574
 
 
575
 
  /* change state only to what's needed */
576
 
  gst_element_set_state (demux, target);
577
 
  gst_element_set_state (session, target);
578
 
 
579
 
  return sess;
580
 
 
581
 
  /* ERRORS */
582
 
no_session:
583
 
  {
584
 
    g_warning ("gstrtpbin: could not create gstrtpsession element");
585
 
    return NULL;
586
 
  }
587
 
no_demux:
588
 
  {
589
 
    gst_object_unref (session);
590
 
    g_warning ("gstrtpbin: could not create gstrtpssrcdemux element");
591
 
    return NULL;
592
 
  }
593
 
}
594
 
 
595
 
static void
596
 
free_session (GstRtpBinSession * sess, GstRtpBin * bin)
597
 
{
598
 
  GST_DEBUG_OBJECT (bin, "freeing session %p", sess);
599
 
 
600
 
  gst_element_set_state (sess->demux, GST_STATE_NULL);
601
 
  gst_element_set_state (sess->session, GST_STATE_NULL);
602
 
 
603
 
  if (sess->recv_rtp_sink != NULL) {
604
 
    gst_element_release_request_pad (sess->session, sess->recv_rtp_sink);
605
 
    gst_object_unref (sess->recv_rtp_sink);
606
 
  }
607
 
  if (sess->recv_rtp_src != NULL)
608
 
    gst_object_unref (sess->recv_rtp_src);
609
 
  if (sess->recv_rtcp_sink != NULL) {
610
 
    gst_element_release_request_pad (sess->session, sess->recv_rtcp_sink);
611
 
    gst_object_unref (sess->recv_rtcp_sink);
612
 
  }
613
 
  if (sess->sync_src != NULL)
614
 
    gst_object_unref (sess->sync_src);
615
 
  if (sess->send_rtp_sink != NULL) {
616
 
    gst_element_release_request_pad (sess->session, sess->send_rtp_sink);
617
 
    gst_object_unref (sess->send_rtp_sink);
618
 
  }
619
 
  if (sess->send_rtp_src != NULL)
620
 
    gst_object_unref (sess->send_rtp_src);
621
 
  if (sess->send_rtcp_src != NULL) {
622
 
    gst_element_release_request_pad (sess->session, sess->send_rtcp_src);
623
 
    gst_object_unref (sess->send_rtcp_src);
624
 
  }
625
 
 
626
 
  gst_bin_remove (GST_BIN_CAST (bin), sess->session);
627
 
  gst_bin_remove (GST_BIN_CAST (bin), sess->demux);
628
 
 
629
 
  g_slist_foreach (sess->streams, (GFunc) free_stream, NULL);
630
 
  g_slist_free (sess->streams);
631
 
 
632
 
  g_mutex_free (sess->lock);
633
 
  g_hash_table_destroy (sess->ptmap);
634
 
 
635
 
  g_free (sess);
636
 
}
637
 
 
638
 
/* get the payload type caps for the specific payload @pt in @session */
639
 
static GstCaps *
640
 
get_pt_map (GstRtpBinSession * session, guint pt)
641
 
{
642
 
  GstCaps *caps = NULL;
643
 
  GstRtpBin *bin;
644
 
  GValue ret = { 0 };
645
 
  GValue args[3] = { {0}, {0}, {0} };
646
 
 
647
 
  GST_DEBUG ("searching pt %d in cache", pt);
648
 
 
649
 
  GST_RTP_SESSION_LOCK (session);
650
 
 
651
 
  /* first look in the cache */
652
 
  caps = g_hash_table_lookup (session->ptmap, GINT_TO_POINTER (pt));
653
 
  if (caps) {
654
 
    gst_caps_ref (caps);
655
 
    goto done;
656
 
  }
657
 
 
658
 
  bin = session->bin;
659
 
 
660
 
  GST_DEBUG ("emiting signal for pt %d in session %d", pt, session->id);
661
 
 
662
 
  /* not in cache, send signal to request caps */
663
 
  g_value_init (&args[0], GST_TYPE_ELEMENT);
664
 
  g_value_set_object (&args[0], bin);
665
 
  g_value_init (&args[1], G_TYPE_UINT);
666
 
  g_value_set_uint (&args[1], session->id);
667
 
  g_value_init (&args[2], G_TYPE_UINT);
668
 
  g_value_set_uint (&args[2], pt);
669
 
 
670
 
  g_value_init (&ret, GST_TYPE_CAPS);
671
 
  g_value_set_boxed (&ret, NULL);
672
 
 
673
 
  GST_RTP_SESSION_UNLOCK (session);
674
 
 
675
 
  g_signal_emitv (args, gst_rtp_bin_signals[SIGNAL_REQUEST_PT_MAP], 0, &ret);
676
 
 
677
 
  GST_RTP_SESSION_LOCK (session);
678
 
 
679
 
  g_value_unset (&args[0]);
680
 
  g_value_unset (&args[1]);
681
 
  g_value_unset (&args[2]);
682
 
 
683
 
  /* look in the cache again because we let the lock go */
684
 
  caps = g_hash_table_lookup (session->ptmap, GINT_TO_POINTER (pt));
685
 
  if (caps) {
686
 
    gst_caps_ref (caps);
687
 
    g_value_unset (&ret);
688
 
    goto done;
689
 
  }
690
 
 
691
 
  caps = (GstCaps *) g_value_dup_boxed (&ret);
692
 
  g_value_unset (&ret);
693
 
  if (!caps)
694
 
    goto no_caps;
695
 
 
696
 
  GST_DEBUG ("caching pt %d as %" GST_PTR_FORMAT, pt, caps);
697
 
 
698
 
  /* store in cache, take additional ref */
699
 
  g_hash_table_insert (session->ptmap, GINT_TO_POINTER (pt),
700
 
      gst_caps_ref (caps));
701
 
 
702
 
done:
703
 
  GST_RTP_SESSION_UNLOCK (session);
704
 
 
705
 
  return caps;
706
 
 
707
 
  /* ERRORS */
708
 
no_caps:
709
 
  {
710
 
    GST_RTP_SESSION_UNLOCK (session);
711
 
    GST_DEBUG ("no pt map could be obtained");
712
 
    return NULL;
713
 
  }
714
 
}
715
 
 
716
 
static gboolean
717
 
return_true (gpointer key, gpointer value, gpointer user_data)
718
 
{
719
 
  return TRUE;
720
 
}
721
 
 
722
 
static void
723
 
gst_rtp_bin_reset_sync (GstRtpBin * rtpbin)
724
 
{
725
 
  GSList *clients, *streams;
726
 
 
727
 
  GST_DEBUG_OBJECT (rtpbin, "Reset sync on all clients");
728
 
 
729
 
  GST_RTP_BIN_LOCK (rtpbin);
730
 
  for (clients = rtpbin->clients; clients; clients = g_slist_next (clients)) {
731
 
    GstRtpBinClient *client = (GstRtpBinClient *) clients->data;
732
 
 
733
 
    /* reset sync on all streams for this client */
734
 
    for (streams = client->streams; streams; streams = g_slist_next (streams)) {
735
 
      GstRtpBinStream *stream = (GstRtpBinStream *) streams->data;
736
 
 
737
 
      /* make use require a new SR packet for this stream before we attempt new
738
 
       * lip-sync */
739
 
      stream->have_sync = FALSE;
740
 
      stream->unix_delta = 0;
741
 
    }
742
 
  }
743
 
  GST_RTP_BIN_UNLOCK (rtpbin);
744
 
}
745
 
 
746
 
static void
747
 
gst_rtp_bin_clear_pt_map (GstRtpBin * bin)
748
 
{
749
 
  GSList *sessions, *streams;
750
 
 
751
 
  GST_RTP_BIN_LOCK (bin);
752
 
  GST_DEBUG_OBJECT (bin, "clearing pt map");
753
 
  for (sessions = bin->sessions; sessions; sessions = g_slist_next (sessions)) {
754
 
    GstRtpBinSession *session = (GstRtpBinSession *) sessions->data;
755
 
 
756
 
    GST_DEBUG_OBJECT (bin, "clearing session %p", session);
757
 
    g_signal_emit_by_name (session->session, "clear-pt-map", NULL);
758
 
 
759
 
    GST_RTP_SESSION_LOCK (session);
760
 
    g_hash_table_foreach_remove (session->ptmap, return_true, NULL);
761
 
 
762
 
    for (streams = session->streams; streams; streams = g_slist_next (streams)) {
763
 
      GstRtpBinStream *stream = (GstRtpBinStream *) streams->data;
764
 
 
765
 
      GST_DEBUG_OBJECT (bin, "clearing stream %p", stream);
766
 
      g_signal_emit_by_name (stream->buffer, "clear-pt-map", NULL);
767
 
      g_signal_emit_by_name (stream->demux, "clear-pt-map", NULL);
768
 
    }
769
 
    GST_RTP_SESSION_UNLOCK (session);
770
 
  }
771
 
  GST_RTP_BIN_UNLOCK (bin);
772
 
 
773
 
  /* reset sync too */
774
 
  gst_rtp_bin_reset_sync (bin);
775
 
}
776
 
 
777
 
static RTPSession *
778
 
gst_rtp_bin_get_internal_session (GstRtpBin * bin, guint session_id)
779
 
{
780
 
  RTPSession *internal_session = NULL;
781
 
  GstRtpBinSession *session;
782
 
 
783
 
  GST_RTP_BIN_LOCK (bin);
784
 
  GST_DEBUG_OBJECT (bin, "retrieving internal RTPSession object, index: %d",
785
 
      session_id);
786
 
  session = find_session_by_id (bin, (gint) session_id);
787
 
  if (session) {
788
 
    g_object_get (session->session, "internal-session", &internal_session,
789
 
        NULL);
790
 
  }
791
 
  GST_RTP_BIN_UNLOCK (bin);
792
 
 
793
 
  return internal_session;
794
 
}
795
 
 
796
 
static void
797
 
gst_rtp_bin_propagate_property_to_jitterbuffer (GstRtpBin * bin,
798
 
    const gchar * name, const GValue * value)
799
 
{
800
 
  GSList *sessions, *streams;
801
 
 
802
 
  GST_RTP_BIN_LOCK (bin);
803
 
  for (sessions = bin->sessions; sessions; sessions = g_slist_next (sessions)) {
804
 
    GstRtpBinSession *session = (GstRtpBinSession *) sessions->data;
805
 
 
806
 
    GST_RTP_SESSION_LOCK (session);
807
 
    for (streams = session->streams; streams; streams = g_slist_next (streams)) {
808
 
      GstRtpBinStream *stream = (GstRtpBinStream *) streams->data;
809
 
 
810
 
      g_object_set_property (G_OBJECT (stream->buffer), name, value);
811
 
    }
812
 
    GST_RTP_SESSION_UNLOCK (session);
813
 
  }
814
 
  GST_RTP_BIN_UNLOCK (bin);
815
 
}
816
 
 
817
 
/* get a client with the given SDES name. Must be called with RTP_BIN_LOCK */
818
 
static GstRtpBinClient *
819
 
get_client (GstRtpBin * bin, guint8 len, guint8 * data, gboolean * created)
820
 
{
821
 
  GstRtpBinClient *result = NULL;
822
 
  GSList *walk;
823
 
 
824
 
  for (walk = bin->clients; walk; walk = g_slist_next (walk)) {
825
 
    GstRtpBinClient *client = (GstRtpBinClient *) walk->data;
826
 
 
827
 
    if (len != client->cname_len)
828
 
      continue;
829
 
 
830
 
    if (!strncmp ((gchar *) data, client->cname, client->cname_len)) {
831
 
      GST_DEBUG_OBJECT (bin, "found existing client %p with CNAME %s", client,
832
 
          client->cname);
833
 
      result = client;
834
 
      break;
835
 
    }
836
 
  }
837
 
 
838
 
  /* nothing found, create one */
839
 
  if (result == NULL) {
840
 
    result = g_new0 (GstRtpBinClient, 1);
841
 
    result->cname = g_strndup ((gchar *) data, len);
842
 
    result->cname_len = len;
843
 
    bin->clients = g_slist_prepend (bin->clients, result);
844
 
    GST_DEBUG_OBJECT (bin, "created new client %p with CNAME %s", result,
845
 
        result->cname);
846
 
  }
847
 
  return result;
848
 
}
849
 
 
850
 
static void
851
 
free_client (GstRtpBinClient * client, GstRtpBin * bin)
852
 
{
853
 
  GST_DEBUG_OBJECT (bin, "freeing client %p", client);
854
 
  g_slist_free (client->streams);
855
 
  g_free (client->cname);
856
 
  g_free (client);
857
 
}
858
 
 
859
 
/* associate a stream to the given CNAME. This will make sure all streams for
860
 
 * that CNAME are synchronized together.
861
 
 * Must be called with GST_RTP_BIN_LOCK */
862
 
static void
863
 
gst_rtp_bin_associate (GstRtpBin * bin, GstRtpBinStream * stream, guint8 len,
864
 
    guint8 * data, guint64 last_unix, guint64 last_extrtptime,
865
 
    guint64 clock_base, guint64 clock_base_time, guint clock_rate)
866
 
{
867
 
  GstRtpBinClient *client;
868
 
  gboolean created;
869
 
  GSList *walk;
870
 
  guint64 local_unix;
871
 
  guint64 local_rtp;
872
 
 
873
 
  /* first find or create the CNAME */
874
 
  client = get_client (bin, len, data, &created);
875
 
 
876
 
  /* find stream in the client */
877
 
  for (walk = client->streams; walk; walk = g_slist_next (walk)) {
878
 
    GstRtpBinStream *ostream = (GstRtpBinStream *) walk->data;
879
 
 
880
 
    if (ostream == stream)
881
 
      break;
882
 
  }
883
 
  /* not found, add it to the list */
884
 
  if (walk == NULL) {
885
 
    GST_DEBUG_OBJECT (bin,
886
 
        "new association of SSRC %08x with client %p with CNAME %s",
887
 
        stream->ssrc, client, client->cname);
888
 
    client->streams = g_slist_prepend (client->streams, stream);
889
 
    client->nstreams++;
890
 
  } else {
891
 
    GST_DEBUG_OBJECT (bin,
892
 
        "found association of SSRC %08x with client %p with CNAME %s",
893
 
        stream->ssrc, client, client->cname);
894
 
  }
895
 
 
896
 
  /* take the extended rtptime we found in the SR packet and map it to the
897
 
   * local rtptime. The local rtp time is used to construct timestamps on the
898
 
   * buffers. */
899
 
  local_rtp = last_extrtptime - clock_base;
900
 
 
901
 
  GST_DEBUG_OBJECT (bin,
902
 
      "base %" G_GUINT64_FORMAT ", extrtptime %" G_GUINT64_FORMAT
903
 
      ", local RTP %" G_GUINT64_FORMAT ", clock-rate %d", clock_base,
904
 
      last_extrtptime, local_rtp, clock_rate);
905
 
 
906
 
  /* calculate local NTP time in gstreamer timestamp, we essentially perform the
907
 
   * same conversion that a jitterbuffer would use to convert an rtp timestamp
908
 
   * into a corresponding gstreamer timestamp. */
909
 
  local_unix = gst_util_uint64_scale_int (local_rtp, GST_SECOND, clock_rate);
910
 
  local_unix += clock_base_time;
911
 
 
912
 
  /* calculate delta between server and receiver. last_unix is created by
913
 
   * converting the ntptime in the last SR packet to a gstreamer timestamp. This
914
 
   * delta expresses the difference to our timeline and the server timeline. */
915
 
  stream->unix_delta = last_unix - local_unix;
916
 
  stream->have_sync = TRUE;
917
 
 
918
 
  GST_DEBUG_OBJECT (bin,
919
 
      "local UNIX %" G_GUINT64_FORMAT ", remote UNIX %" G_GUINT64_FORMAT
920
 
      ", delta %" G_GINT64_FORMAT, local_unix, last_unix, stream->unix_delta);
921
 
 
922
 
  /* recalc inter stream playout offset, but only if there is more than one
923
 
   * stream. */
924
 
  if (client->nstreams > 1) {
925
 
    gint64 min;
926
 
 
927
 
    /* calculate the min of all deltas, ignoring streams that did not yet have a
928
 
     * valid unix_delta because we did not yet receive an SR packet for those
929
 
     * streams. 
930
 
     * We calculate the mininum because we would like to only apply positive
931
 
     * offsets to streams, delaying their playback instead of trying to speed up
932
 
     * other streams (which might be imposible when we have to create negative
933
 
     * latencies).
934
 
     * The stream that has the smallest diff is selected as the reference stream,
935
 
     * all other streams will have a positive offset to this difference. */
936
 
    min = G_MAXINT64;
937
 
    for (walk = client->streams; walk; walk = g_slist_next (walk)) {
938
 
      GstRtpBinStream *ostream = (GstRtpBinStream *) walk->data;
939
 
 
940
 
      if (!ostream->have_sync)
941
 
        continue;
942
 
 
943
 
      if (ostream->unix_delta < min)
944
 
        min = ostream->unix_delta;
945
 
    }
946
 
 
947
 
    GST_DEBUG_OBJECT (bin, "client %p min delta %" G_GINT64_FORMAT, client,
948
 
        min);
949
 
 
950
 
    /* calculate offsets for each stream */
951
 
    for (walk = client->streams; walk; walk = g_slist_next (walk)) {
952
 
      GstRtpBinStream *ostream = (GstRtpBinStream *) walk->data;
953
 
      gint64 ts_offset, prev_ts_offset;
954
 
 
955
 
      /* ignore streams for which we didn't receive an SR packet yet, we
956
 
       * can't synchronize them yet. We can however sync other streams just
957
 
       * fine. */
958
 
      if (!ostream->have_sync)
959
 
        continue;
960
 
 
961
 
      /* calculate offset to our reference stream, this should always give a
962
 
       * positive number. */
963
 
      ts_offset = ostream->unix_delta - min;
964
 
 
965
 
      g_object_get (ostream->buffer, "ts-offset", &prev_ts_offset, NULL);
966
 
 
967
 
      /* delta changed, see how much */
968
 
      if (prev_ts_offset != ts_offset) {
969
 
        gint64 diff;
970
 
 
971
 
        if (prev_ts_offset > ts_offset)
972
 
          diff = prev_ts_offset - ts_offset;
973
 
        else
974
 
          diff = ts_offset - prev_ts_offset;
975
 
 
976
 
        GST_DEBUG_OBJECT (bin,
977
 
            "ts-offset %" G_GUINT64_FORMAT ", prev %" G_GUINT64_FORMAT
978
 
            ", diff: %" G_GINT64_FORMAT, ts_offset, prev_ts_offset, diff);
979
 
 
980
 
        /* only change diff when it changed more than 4 milliseconds. This
981
 
         * compensates for rounding errors in NTP to RTP timestamp
982
 
         * conversions */
983
 
        if (diff > 4 * GST_MSECOND && diff < (3 * GST_SECOND)) {
984
 
          g_object_set (ostream->buffer, "ts-offset", ts_offset, NULL);
985
 
        }
986
 
      }
987
 
      GST_DEBUG_OBJECT (bin, "stream SSRC %08x, delta %" G_GINT64_FORMAT,
988
 
          ostream->ssrc, ts_offset);
989
 
    }
990
 
  }
991
 
  return;
992
 
}
993
 
 
994
 
#define GST_RTCP_BUFFER_FOR_PACKETS(b,buffer,packet) \
995
 
  for ((b) = gst_rtcp_buffer_get_first_packet ((buffer), (packet)); (b); \
996
 
          (b) = gst_rtcp_packet_move_to_next ((packet)))
997
 
 
998
 
#define GST_RTCP_SDES_FOR_ITEMS(b,packet) \
999
 
  for ((b) = gst_rtcp_packet_sdes_first_item ((packet)); (b); \
1000
 
          (b) = gst_rtcp_packet_sdes_next_item ((packet)))
1001
 
 
1002
 
#define GST_RTCP_SDES_FOR_ENTRIES(b,packet) \
1003
 
  for ((b) = gst_rtcp_packet_sdes_first_entry ((packet)); (b); \
1004
 
          (b) = gst_rtcp_packet_sdes_next_entry ((packet)))
1005
 
 
1006
 
static void
1007
 
gst_rtp_bin_handle_sync (GstElement * jitterbuffer, GstStructure * s,
1008
 
    GstRtpBinStream * stream)
1009
 
{
1010
 
  GstRtpBin *bin;
1011
 
  GstRTCPPacket packet;
1012
 
  guint32 ssrc;
1013
 
  guint64 ntptime;
1014
 
  gboolean have_sr, have_sdes;
1015
 
  gboolean more;
1016
 
  guint64 clock_base;
1017
 
  guint64 clock_base_time;
1018
 
  guint clock_rate;
1019
 
  guint64 extrtptime;
1020
 
  GstBuffer *buffer;
1021
 
 
1022
 
  bin = stream->bin;
1023
 
 
1024
 
  GST_DEBUG_OBJECT (bin, "sync handler called");
1025
 
 
1026
 
  /* get the last relation between the rtp timestamps and the gstreamer
1027
 
   * timestamps. We get this info directly from the jitterbuffer which
1028
 
   * constructs gstreamer timestamps from rtp timestamps and so it know exactly
1029
 
   * what the current situation is. */
1030
 
  clock_base = g_value_get_uint64 (gst_structure_get_value (s, "base-rtptime"));
1031
 
  clock_base_time =
1032
 
      g_value_get_uint64 (gst_structure_get_value (s, "base-time"));
1033
 
  clock_rate = g_value_get_uint (gst_structure_get_value (s, "clock-rate"));
1034
 
  extrtptime =
1035
 
      g_value_get_uint64 (gst_structure_get_value (s, "sr-ext-rtptime"));
1036
 
  buffer = gst_value_get_buffer (gst_structure_get_value (s, "sr-buffer"));
1037
 
 
1038
 
  have_sr = FALSE;
1039
 
  have_sdes = FALSE;
1040
 
  GST_RTCP_BUFFER_FOR_PACKETS (more, buffer, &packet) {
1041
 
    /* first packet must be SR or RR or else the validate would have failed */
1042
 
    switch (gst_rtcp_packet_get_type (&packet)) {
1043
 
      case GST_RTCP_TYPE_SR:
1044
 
        /* only parse first. There is only supposed to be one SR in the packet
1045
 
         * but we will deal with malformed packets gracefully */
1046
 
        if (have_sr)
1047
 
          break;
1048
 
        /* get NTP and RTP times */
1049
 
        gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, &ntptime, NULL,
1050
 
            NULL, NULL);
1051
 
 
1052
 
        GST_DEBUG_OBJECT (bin, "received sync packet from SSRC %08x", ssrc);
1053
 
        /* ignore SR that is not ours */
1054
 
        if (ssrc != stream->ssrc)
1055
 
          continue;
1056
 
 
1057
 
        have_sr = TRUE;
1058
 
        break;
1059
 
      case GST_RTCP_TYPE_SDES:
1060
 
      {
1061
 
        gboolean more_items, more_entries;
1062
 
 
1063
 
        /* only deal with first SDES, there is only supposed to be one SDES in
1064
 
         * the RTCP packet but we deal with bad packets gracefully. Also bail
1065
 
         * out if we have not seen an SR item yet. */
1066
 
        if (have_sdes || !have_sr)
1067
 
          break;
1068
 
 
1069
 
        GST_RTCP_SDES_FOR_ITEMS (more_items, &packet) {
1070
 
          /* skip items that are not about the SSRC of the sender */
1071
 
          if (gst_rtcp_packet_sdes_get_ssrc (&packet) != ssrc)
1072
 
            continue;
1073
 
 
1074
 
          /* find the CNAME entry */
1075
 
          GST_RTCP_SDES_FOR_ENTRIES (more_entries, &packet) {
1076
 
            GstRTCPSDESType type;
1077
 
            guint8 len;
1078
 
            guint8 *data;
1079
 
 
1080
 
            gst_rtcp_packet_sdes_get_entry (&packet, &type, &len, &data);
1081
 
 
1082
 
            if (type == GST_RTCP_SDES_CNAME) {
1083
 
              GST_RTP_BIN_LOCK (bin);
1084
 
              /* associate the stream to CNAME */
1085
 
              gst_rtp_bin_associate (bin, stream, len, data,
1086
 
                  gst_rtcp_ntp_to_unix (ntptime), extrtptime,
1087
 
                  clock_base, clock_base_time, clock_rate);
1088
 
              GST_RTP_BIN_UNLOCK (bin);
1089
 
            }
1090
 
          }
1091
 
        }
1092
 
        have_sdes = TRUE;
1093
 
        break;
1094
 
      }
1095
 
      default:
1096
 
        /* we can ignore these packets */
1097
 
        break;
1098
 
    }
1099
 
  }
1100
 
}
1101
 
 
1102
 
/* create a new stream with @ssrc in @session. Must be called with
1103
 
 * RTP_SESSION_LOCK. */
1104
 
static GstRtpBinStream *
1105
 
create_stream (GstRtpBinSession * session, guint32 ssrc)
1106
 
{
1107
 
  GstElement *buffer, *demux;
1108
 
  GstRtpBinStream *stream;
1109
 
  GstRtpBin *rtpbin;
1110
 
  GstState target;
1111
 
 
1112
 
  if (!(buffer = gst_element_factory_make ("gstrtpjitterbuffer", NULL)))
1113
 
    goto no_jitterbuffer;
1114
 
 
1115
 
  if (!(demux = gst_element_factory_make ("gstrtpptdemux", NULL)))
1116
 
    goto no_demux;
1117
 
 
1118
 
  rtpbin = session->bin;
1119
 
 
1120
 
  stream = g_new0 (GstRtpBinStream, 1);
1121
 
  stream->ssrc = ssrc;
1122
 
  stream->bin = rtpbin;
1123
 
  stream->session = session;
1124
 
  stream->buffer = buffer;
1125
 
  stream->demux = demux;
1126
 
  stream->have_sync = FALSE;
1127
 
  stream->unix_delta = 0;
1128
 
  session->streams = g_slist_prepend (session->streams, stream);
1129
 
 
1130
 
  /* provide clock_rate to the jitterbuffer when needed */
1131
 
  stream->buffer_ptreq_sig = g_signal_connect (buffer, "request-pt-map",
1132
 
      (GCallback) pt_map_requested, session);
1133
 
  stream->buffer_ntpstop_sig = g_signal_connect (buffer, "on-npt-stop",
1134
 
      (GCallback) on_npt_stop, stream);
1135
 
 
1136
 
  /* configure latency and packet lost */
1137
 
  g_object_set (buffer, "latency", rtpbin->latency, NULL);
1138
 
  g_object_set (buffer, "do-lost", rtpbin->do_lost, NULL);
1139
 
 
1140
 
  gst_bin_add (GST_BIN_CAST (rtpbin), demux);
1141
 
  gst_bin_add (GST_BIN_CAST (rtpbin), buffer);
1142
 
 
1143
 
  /* link stuff */
1144
 
  gst_element_link (buffer, demux);
1145
 
 
1146
 
  GST_OBJECT_LOCK (rtpbin);
1147
 
  target = GST_STATE_TARGET (rtpbin);
1148
 
  GST_OBJECT_UNLOCK (rtpbin);
1149
 
 
1150
 
  /* from sink to source */
1151
 
  gst_element_set_state (demux, target);
1152
 
  gst_element_set_state (buffer, target);
1153
 
 
1154
 
  return stream;
1155
 
 
1156
 
  /* ERRORS */
1157
 
no_jitterbuffer:
1158
 
  {
1159
 
    g_warning ("gstrtpbin: could not create gstrtpjitterbuffer element");
1160
 
    return NULL;
1161
 
  }
1162
 
no_demux:
1163
 
  {
1164
 
    gst_object_unref (buffer);
1165
 
    g_warning ("gstrtpbin: could not create gstrtpptdemux element");
1166
 
    return NULL;
1167
 
  }
1168
 
}
1169
 
 
1170
 
static void
1171
 
free_stream (GstRtpBinStream * stream)
1172
 
{
1173
 
  GstRtpBinSession *session;
1174
 
  GSList *walk;
1175
 
 
1176
 
  session = stream->session;
1177
 
 
1178
 
  g_signal_handler_disconnect (stream->demux, stream->demux_newpad_sig);
1179
 
  g_signal_handler_disconnect (stream->demux, stream->demux_ptreq_sig);
1180
 
  g_signal_handler_disconnect (stream->buffer, stream->buffer_handlesync_sig);
1181
 
  g_signal_handler_disconnect (stream->buffer, stream->buffer_ptreq_sig);
1182
 
  g_signal_handler_disconnect (stream->buffer, stream->buffer_ntpstop_sig);
1183
 
 
1184
 
  gst_element_set_state (stream->demux, GST_STATE_NULL);
1185
 
  gst_element_set_state (stream->buffer, GST_STATE_NULL);
1186
 
 
1187
 
  gst_bin_remove (GST_BIN_CAST (session->bin), stream->buffer);
1188
 
  gst_bin_remove (GST_BIN_CAST (session->bin), stream->demux);
1189
 
 
1190
 
  for (walk = stream->pads; walk; walk = g_slist_next (walk)) {
1191
 
    GstPad *gpad = GST_PAD_CAST (walk->data);
1192
 
 
1193
 
    gst_pad_set_active (gpad, FALSE);
1194
 
    gst_element_remove_pad (GST_ELEMENT_CAST (session->bin), gpad);
1195
 
  }
1196
 
  g_slist_free (stream->pads);
1197
 
 
1198
 
  g_free (stream);
1199
 
}
1200
 
 
1201
 
/* GObject vmethods */
1202
 
static void gst_rtp_bin_dispose (GObject * object);
1203
 
static void gst_rtp_bin_finalize (GObject * object);
1204
 
static void gst_rtp_bin_set_property (GObject * object, guint prop_id,
1205
 
    const GValue * value, GParamSpec * pspec);
1206
 
static void gst_rtp_bin_get_property (GObject * object, guint prop_id,
1207
 
    GValue * value, GParamSpec * pspec);
1208
 
 
1209
 
/* GstElement vmethods */
1210
 
static GstStateChangeReturn gst_rtp_bin_change_state (GstElement * element,
1211
 
    GstStateChange transition);
1212
 
static GstPad *gst_rtp_bin_request_new_pad (GstElement * element,
1213
 
    GstPadTemplate * templ, const gchar * name);
1214
 
static void gst_rtp_bin_release_pad (GstElement * element, GstPad * pad);
1215
 
static void gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message);
1216
 
static void gst_rtp_bin_clear_pt_map (GstRtpBin * bin);
1217
 
 
1218
 
GST_BOILERPLATE (GstRtpBin, gst_rtp_bin, GstBin, GST_TYPE_BIN);
1219
 
 
1220
 
static void
1221
 
gst_rtp_bin_base_init (gpointer klass)
1222
 
{
1223
 
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
1224
 
 
1225
 
  /* sink pads */
1226
 
  gst_element_class_add_pad_template (element_class,
1227
 
      gst_static_pad_template_get (&rtpbin_recv_rtp_sink_template));
1228
 
  gst_element_class_add_pad_template (element_class,
1229
 
      gst_static_pad_template_get (&rtpbin_recv_rtcp_sink_template));
1230
 
  gst_element_class_add_pad_template (element_class,
1231
 
      gst_static_pad_template_get (&rtpbin_send_rtp_sink_template));
1232
 
 
1233
 
  /* src pads */
1234
 
  gst_element_class_add_pad_template (element_class,
1235
 
      gst_static_pad_template_get (&rtpbin_recv_rtp_src_template));
1236
 
  gst_element_class_add_pad_template (element_class,
1237
 
      gst_static_pad_template_get (&rtpbin_send_rtcp_src_template));
1238
 
  gst_element_class_add_pad_template (element_class,
1239
 
      gst_static_pad_template_get (&rtpbin_send_rtp_src_template));
1240
 
 
1241
 
  gst_element_class_set_details (element_class, &rtpbin_details);
1242
 
}
1243
 
 
1244
 
static void
1245
 
gst_rtp_bin_class_init (GstRtpBinClass * klass)
1246
 
{
1247
 
  GObjectClass *gobject_class;
1248
 
  GstElementClass *gstelement_class;
1249
 
  GstBinClass *gstbin_class;
1250
 
 
1251
 
  gobject_class = (GObjectClass *) klass;
1252
 
  gstelement_class = (GstElementClass *) klass;
1253
 
  gstbin_class = (GstBinClass *) klass;
1254
 
 
1255
 
  g_type_class_add_private (klass, sizeof (GstRtpBinPrivate));
1256
 
 
1257
 
  gobject_class->dispose = gst_rtp_bin_dispose;
1258
 
  gobject_class->finalize = gst_rtp_bin_finalize;
1259
 
  gobject_class->set_property = gst_rtp_bin_set_property;
1260
 
  gobject_class->get_property = gst_rtp_bin_get_property;
1261
 
 
1262
 
  g_object_class_install_property (gobject_class, PROP_LATENCY,
1263
 
      g_param_spec_uint ("latency", "Buffer latency in ms",
1264
 
          "Default amount of ms to buffer in the jitterbuffers", 0,
1265
 
          G_MAXUINT, DEFAULT_LATENCY_MS, G_PARAM_READWRITE));
1266
 
 
1267
 
  /**
1268
 
   * GstRtpBin::request-pt-map:
1269
 
   * @rtpbin: the object which received the signal
1270
 
   * @session: the session
1271
 
   * @pt: the pt
1272
 
   *
1273
 
   * Request the payload type as #GstCaps for @pt in @session.
1274
 
   */
1275
 
  gst_rtp_bin_signals[SIGNAL_REQUEST_PT_MAP] =
1276
 
      g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
1277
 
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, request_pt_map),
1278
 
      NULL, NULL, gst_rtp_bin_marshal_BOXED__UINT_UINT, GST_TYPE_CAPS, 2,
1279
 
      G_TYPE_UINT, G_TYPE_UINT);
1280
 
  /**
1281
 
   * GstRtpBin::clear-pt-map:
1282
 
   * @rtpbin: the object which received the signal
1283
 
   *
1284
 
   * Clear all previously cached pt-mapping obtained with
1285
 
   * #GstRtpBin::request-pt-map.
1286
 
   */
1287
 
  gst_rtp_bin_signals[SIGNAL_CLEAR_PT_MAP] =
1288
 
      g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
1289
 
      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRtpBinClass,
1290
 
          clear_pt_map), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE,
1291
 
      0, G_TYPE_NONE);
1292
 
  /**
1293
 
   * GstRtpBin::reset-sync:
1294
 
   * @rtpbin: the object which received the signal
1295
 
   *
1296
 
   * Reset all currently configured lip-sync parameters and require new SR
1297
 
   * packets for all streams before lip-sync is attempted again.
1298
 
   */
1299
 
  gst_rtp_bin_signals[SIGNAL_RESET_SYNC] =
1300
 
      g_signal_new ("reset-sync", G_TYPE_FROM_CLASS (klass),
1301
 
      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRtpBinClass,
1302
 
          reset_sync), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE,
1303
 
      0, G_TYPE_NONE);
1304
 
 
1305
 
  /**
1306
 
   * GstRtpBin::get-internal-session:
1307
 
   * @rtpbin: the object which received the signal
1308
 
   * @id: the session id
1309
 
   *
1310
 
   * Request the internal RTPSession object as #GObject in session @id.
1311
 
   */
1312
 
  gst_rtp_bin_signals[SIGNAL_GET_INTERNAL_SESSION] =
1313
 
      g_signal_new ("get-internal-session", G_TYPE_FROM_CLASS (klass),
1314
 
      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRtpBinClass,
1315
 
          get_internal_session), NULL, NULL, gst_rtp_bin_marshal_OBJECT__UINT,
1316
 
      RTP_TYPE_SESSION, 1, G_TYPE_UINT);
1317
 
 
1318
 
  /**
1319
 
   * GstRtpBin::on-new-ssrc:
1320
 
   * @rtpbin: the object which received the signal
1321
 
   * @session: the session
1322
 
   * @ssrc: the SSRC 
1323
 
   *
1324
 
   * Notify of a new SSRC that entered @session.
1325
 
   */
1326
 
  gst_rtp_bin_signals[SIGNAL_ON_NEW_SSRC] =
1327
 
      g_signal_new ("on-new-ssrc", G_TYPE_FROM_CLASS (klass),
1328
 
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_new_ssrc),
1329
 
      NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1330
 
      G_TYPE_UINT, G_TYPE_UINT);
1331
 
  /**
1332
 
   * GstRtpBin::on-ssrc-collision:
1333
 
   * @rtpbin: the object which received the signal
1334
 
   * @session: the session
1335
 
   * @ssrc: the SSRC 
1336
 
   *
1337
 
   * Notify when we have an SSRC collision
1338
 
   */
1339
 
  gst_rtp_bin_signals[SIGNAL_ON_SSRC_COLLISION] =
1340
 
      g_signal_new ("on-ssrc-collision", G_TYPE_FROM_CLASS (klass),
1341
 
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_ssrc_collision),
1342
 
      NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1343
 
      G_TYPE_UINT, G_TYPE_UINT);
1344
 
  /**
1345
 
   * GstRtpBin::on-ssrc-validated:
1346
 
   * @rtpbin: the object which received the signal
1347
 
   * @session: the session
1348
 
   * @ssrc: the SSRC 
1349
 
   *
1350
 
   * Notify of a new SSRC that became validated.
1351
 
   */
1352
 
  gst_rtp_bin_signals[SIGNAL_ON_SSRC_VALIDATED] =
1353
 
      g_signal_new ("on-ssrc-validated", G_TYPE_FROM_CLASS (klass),
1354
 
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_ssrc_validated),
1355
 
      NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1356
 
      G_TYPE_UINT, G_TYPE_UINT);
1357
 
  /**
1358
 
   * GstRtpBin::on-ssrc-active:
1359
 
   * @rtpbin: the object which received the signal
1360
 
   * @session: the session
1361
 
   * @ssrc: the SSRC
1362
 
   *
1363
 
   * Notify of a SSRC that is active, i.e., sending RTCP.
1364
 
   */
1365
 
  gst_rtp_bin_signals[SIGNAL_ON_SSRC_ACTIVE] =
1366
 
      g_signal_new ("on-ssrc-active", G_TYPE_FROM_CLASS (klass),
1367
 
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_ssrc_active),
1368
 
      NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1369
 
      G_TYPE_UINT, G_TYPE_UINT);
1370
 
  /**
1371
 
   * GstRtpBin::on-ssrc-sdes:
1372
 
   * @rtpbin: the object which received the signal
1373
 
   * @session: the session
1374
 
   * @ssrc: the SSRC
1375
 
   *
1376
 
   * Notify of a SSRC that is active, i.e., sending RTCP.
1377
 
   */
1378
 
  gst_rtp_bin_signals[SIGNAL_ON_SSRC_SDES] =
1379
 
      g_signal_new ("on-ssrc-sdes", G_TYPE_FROM_CLASS (klass),
1380
 
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_ssrc_sdes),
1381
 
      NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1382
 
      G_TYPE_UINT, G_TYPE_UINT);
1383
 
 
1384
 
  /**
1385
 
   * GstRtpBin::on-bye-ssrc:
1386
 
   * @rtpbin: the object which received the signal
1387
 
   * @session: the session
1388
 
   * @ssrc: the SSRC 
1389
 
   *
1390
 
   * Notify of an SSRC that became inactive because of a BYE packet.
1391
 
   */
1392
 
  gst_rtp_bin_signals[SIGNAL_ON_BYE_SSRC] =
1393
 
      g_signal_new ("on-bye-ssrc", G_TYPE_FROM_CLASS (klass),
1394
 
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_bye_ssrc),
1395
 
      NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1396
 
      G_TYPE_UINT, G_TYPE_UINT);
1397
 
  /**
1398
 
   * GstRtpBin::on-bye-timeout:
1399
 
   * @rtpbin: the object which received the signal
1400
 
   * @session: the session
1401
 
   * @ssrc: the SSRC 
1402
 
   *
1403
 
   * Notify of an SSRC that has timed out because of BYE
1404
 
   */
1405
 
  gst_rtp_bin_signals[SIGNAL_ON_BYE_TIMEOUT] =
1406
 
      g_signal_new ("on-bye-timeout", G_TYPE_FROM_CLASS (klass),
1407
 
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_bye_timeout),
1408
 
      NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1409
 
      G_TYPE_UINT, G_TYPE_UINT);
1410
 
  /**
1411
 
   * GstRtpBin::on-timeout:
1412
 
   * @rtpbin: the object which received the signal
1413
 
   * @session: the session
1414
 
   * @ssrc: the SSRC 
1415
 
   *
1416
 
   * Notify of an SSRC that has timed out
1417
 
   */
1418
 
  gst_rtp_bin_signals[SIGNAL_ON_TIMEOUT] =
1419
 
      g_signal_new ("on-timeout", G_TYPE_FROM_CLASS (klass),
1420
 
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_timeout),
1421
 
      NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1422
 
      G_TYPE_UINT, G_TYPE_UINT);
1423
 
  /**
1424
 
   * GstRtpBin::on-sender-timeout:
1425
 
   * @rtpbin: the object which received the signal
1426
 
   * @session: the session
1427
 
   * @ssrc: the SSRC 
1428
 
   *
1429
 
   * Notify of a sender SSRC that has timed out and became a receiver
1430
 
   */
1431
 
  gst_rtp_bin_signals[SIGNAL_ON_SENDER_TIMEOUT] =
1432
 
      g_signal_new ("on-sender-timeout", G_TYPE_FROM_CLASS (klass),
1433
 
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_sender_timeout),
1434
 
      NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1435
 
      G_TYPE_UINT, G_TYPE_UINT);
1436
 
 
1437
 
  /**
1438
 
   * GstRtpBin::on-npt-stop:
1439
 
   * @rtpbin: the object which received the signal
1440
 
   * @session: the session
1441
 
   * @ssrc: the SSRC 
1442
 
   *
1443
 
   * Notify that SSRC sender has sent data up to the configured NPT stop time.
1444
 
   */
1445
 
  gst_rtp_bin_signals[SIGNAL_ON_NPT_STOP] =
1446
 
      g_signal_new ("on-npt-stop", G_TYPE_FROM_CLASS (klass),
1447
 
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_npt_stop),
1448
 
      NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
1449
 
      G_TYPE_UINT, G_TYPE_UINT);
1450
 
 
1451
 
  g_object_class_install_property (gobject_class, PROP_SDES_CNAME,
1452
 
      g_param_spec_string ("sdes-cname", "SDES CNAME",
1453
 
          "The CNAME to put in SDES messages of this session",
1454
 
          DEFAULT_SDES_CNAME, G_PARAM_READWRITE));
1455
 
 
1456
 
  g_object_class_install_property (gobject_class, PROP_SDES_NAME,
1457
 
      g_param_spec_string ("sdes-name", "SDES NAME",
1458
 
          "The NAME to put in SDES messages of this session",
1459
 
          DEFAULT_SDES_NAME, G_PARAM_READWRITE));
1460
 
 
1461
 
  g_object_class_install_property (gobject_class, PROP_SDES_EMAIL,
1462
 
      g_param_spec_string ("sdes-email", "SDES EMAIL",
1463
 
          "The EMAIL to put in SDES messages of this session",
1464
 
          DEFAULT_SDES_EMAIL, G_PARAM_READWRITE));
1465
 
 
1466
 
  g_object_class_install_property (gobject_class, PROP_SDES_PHONE,
1467
 
      g_param_spec_string ("sdes-phone", "SDES PHONE",
1468
 
          "The PHONE to put in SDES messages of this session",
1469
 
          DEFAULT_SDES_PHONE, G_PARAM_READWRITE));
1470
 
 
1471
 
  g_object_class_install_property (gobject_class, PROP_SDES_LOCATION,
1472
 
      g_param_spec_string ("sdes-location", "SDES LOCATION",
1473
 
          "The LOCATION to put in SDES messages of this session",
1474
 
          DEFAULT_SDES_LOCATION, G_PARAM_READWRITE));
1475
 
 
1476
 
  g_object_class_install_property (gobject_class, PROP_SDES_TOOL,
1477
 
      g_param_spec_string ("sdes-tool", "SDES TOOL",
1478
 
          "The TOOL to put in SDES messages of this session",
1479
 
          DEFAULT_SDES_TOOL, G_PARAM_READWRITE));
1480
 
 
1481
 
  g_object_class_install_property (gobject_class, PROP_SDES_NOTE,
1482
 
      g_param_spec_string ("sdes-note", "SDES NOTE",
1483
 
          "The NOTE to put in SDES messages of this session",
1484
 
          DEFAULT_SDES_NOTE, G_PARAM_READWRITE));
1485
 
 
1486
 
  g_object_class_install_property (gobject_class, PROP_DO_LOST,
1487
 
      g_param_spec_boolean ("do-lost", "Do Lost",
1488
 
          "Send an event downstream when a packet is lost", DEFAULT_DO_LOST,
1489
 
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1490
 
 
1491
 
  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_bin_change_state);
1492
 
  gstelement_class->request_new_pad =
1493
 
      GST_DEBUG_FUNCPTR (gst_rtp_bin_request_new_pad);
1494
 
  gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_bin_release_pad);
1495
 
 
1496
 
  gstbin_class->handle_message = GST_DEBUG_FUNCPTR (gst_rtp_bin_handle_message);
1497
 
 
1498
 
  klass->clear_pt_map = GST_DEBUG_FUNCPTR (gst_rtp_bin_clear_pt_map);
1499
 
  klass->reset_sync = GST_DEBUG_FUNCPTR (gst_rtp_bin_reset_sync);
1500
 
  klass->get_internal_session =
1501
 
      GST_DEBUG_FUNCPTR (gst_rtp_bin_get_internal_session);
1502
 
 
1503
 
  GST_DEBUG_CATEGORY_INIT (gst_rtp_bin_debug, "rtpbin", 0, "RTP bin");
1504
 
}
1505
 
 
1506
 
static void
1507
 
gst_rtp_bin_init (GstRtpBin * rtpbin, GstRtpBinClass * klass)
1508
 
{
1509
 
  gchar *str;
1510
 
 
1511
 
  rtpbin->priv = GST_RTP_BIN_GET_PRIVATE (rtpbin);
1512
 
  rtpbin->priv->bin_lock = g_mutex_new ();
1513
 
  rtpbin->priv->dyn_lock = g_mutex_new ();
1514
 
 
1515
 
  rtpbin->latency = DEFAULT_LATENCY_MS;
1516
 
  rtpbin->do_lost = DEFAULT_DO_LOST;
1517
 
 
1518
 
  /* some default SDES entries */
1519
 
  str = g_strdup_printf ("%s@%s", g_get_user_name (), g_get_host_name ());
1520
 
  gst_rtp_bin_set_sdes_string (rtpbin, GST_RTCP_SDES_CNAME, str);
1521
 
  g_free (str);
1522
 
 
1523
 
  gst_rtp_bin_set_sdes_string (rtpbin, GST_RTCP_SDES_NAME, g_get_real_name ());
1524
 
  gst_rtp_bin_set_sdes_string (rtpbin, GST_RTCP_SDES_TOOL, "GStreamer");
1525
 
}
1526
 
 
1527
 
static void
1528
 
gst_rtp_bin_dispose (GObject * object)
1529
 
{
1530
 
  GstRtpBin *rtpbin;
1531
 
 
1532
 
  rtpbin = GST_RTP_BIN (object);
1533
 
 
1534
 
  GST_DEBUG_OBJECT (object, "freeing sessions");
1535
 
  g_slist_foreach (rtpbin->sessions, (GFunc) free_session, rtpbin);
1536
 
  g_slist_free (rtpbin->sessions);
1537
 
  rtpbin->sessions = NULL;
1538
 
  GST_DEBUG_OBJECT (object, "freeing clients");
1539
 
  g_slist_foreach (rtpbin->clients, (GFunc) free_client, rtpbin);
1540
 
  g_slist_free (rtpbin->clients);
1541
 
  rtpbin->clients = NULL;
1542
 
 
1543
 
  G_OBJECT_CLASS (parent_class)->dispose (object);
1544
 
}
1545
 
 
1546
 
static void
1547
 
gst_rtp_bin_finalize (GObject * object)
1548
 
{
1549
 
  GstRtpBin *rtpbin;
1550
 
  gint i;
1551
 
 
1552
 
  rtpbin = GST_RTP_BIN (object);
1553
 
 
1554
 
  for (i = 0; i < 9; i++)
1555
 
    g_free (rtpbin->sdes[i]);
1556
 
 
1557
 
  g_mutex_free (rtpbin->priv->bin_lock);
1558
 
  g_mutex_free (rtpbin->priv->dyn_lock);
1559
 
 
1560
 
  G_OBJECT_CLASS (parent_class)->finalize (object);
1561
 
}
1562
 
 
1563
 
static const gchar *
1564
 
sdes_type_to_name (GstRTCPSDESType type)
1565
 
{
1566
 
  const gchar *result;
1567
 
 
1568
 
  switch (type) {
1569
 
    case GST_RTCP_SDES_CNAME:
1570
 
      result = "sdes-cname";
1571
 
      break;
1572
 
    case GST_RTCP_SDES_NAME:
1573
 
      result = "sdes-name";
1574
 
      break;
1575
 
    case GST_RTCP_SDES_EMAIL:
1576
 
      result = "sdes-email";
1577
 
      break;
1578
 
    case GST_RTCP_SDES_PHONE:
1579
 
      result = "sdes-phone";
1580
 
      break;
1581
 
    case GST_RTCP_SDES_LOC:
1582
 
      result = "sdes-location";
1583
 
      break;
1584
 
    case GST_RTCP_SDES_TOOL:
1585
 
      result = "sdes-tool";
1586
 
      break;
1587
 
    case GST_RTCP_SDES_NOTE:
1588
 
      result = "sdes-note";
1589
 
      break;
1590
 
    case GST_RTCP_SDES_PRIV:
1591
 
      result = "sdes-priv";
1592
 
      break;
1593
 
    default:
1594
 
      result = NULL;
1595
 
      break;
1596
 
  }
1597
 
  return result;
1598
 
}
1599
 
 
1600
 
static void
1601
 
gst_rtp_bin_set_sdes_string (GstRtpBin * bin, GstRTCPSDESType type,
1602
 
    const gchar * data)
1603
 
{
1604
 
  GSList *item;
1605
 
  const gchar *name;
1606
 
 
1607
 
  if (type < 0 || type > 8)
1608
 
    return;
1609
 
 
1610
 
  GST_RTP_BIN_LOCK (bin);
1611
 
 
1612
 
  GST_OBJECT_LOCK (bin);
1613
 
  g_free (bin->sdes[type]);
1614
 
  bin->sdes[type] = g_strdup (data);
1615
 
  name = sdes_type_to_name (type);
1616
 
  /* store in all sessions */
1617
 
  for (item = bin->sessions; item; item = g_slist_next (item))
1618
 
    g_object_set (item->data, name, bin->sdes[type], NULL);
1619
 
  GST_OBJECT_UNLOCK (bin);
1620
 
 
1621
 
  GST_RTP_BIN_UNLOCK (bin);
1622
 
}
1623
 
 
1624
 
static gchar *
1625
 
gst_rtp_bin_get_sdes_string (GstRtpBin * bin, GstRTCPSDESType type)
1626
 
{
1627
 
  gchar *result;
1628
 
 
1629
 
  if (type < 0 || type > 8)
1630
 
    return NULL;
1631
 
 
1632
 
  GST_OBJECT_LOCK (bin);
1633
 
  result = g_strdup (bin->sdes[type]);
1634
 
  GST_OBJECT_UNLOCK (bin);
1635
 
 
1636
 
  return result;
1637
 
}
1638
 
 
1639
 
static void
1640
 
gst_rtp_bin_set_property (GObject * object, guint prop_id,
1641
 
    const GValue * value, GParamSpec * pspec)
1642
 
{
1643
 
  GstRtpBin *rtpbin;
1644
 
 
1645
 
  rtpbin = GST_RTP_BIN (object);
1646
 
 
1647
 
  switch (prop_id) {
1648
 
    case PROP_LATENCY:
1649
 
      GST_RTP_BIN_LOCK (rtpbin);
1650
 
      rtpbin->latency = g_value_get_uint (value);
1651
 
      GST_RTP_BIN_UNLOCK (rtpbin);
1652
 
      /* propegate the property down to the jitterbuffer */
1653
 
      gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin, "latency", value);
1654
 
      break;
1655
 
    case PROP_SDES_CNAME:
1656
 
      gst_rtp_bin_set_sdes_string (rtpbin, GST_RTCP_SDES_CNAME,
1657
 
          g_value_get_string (value));
1658
 
      break;
1659
 
    case PROP_SDES_NAME:
1660
 
      gst_rtp_bin_set_sdes_string (rtpbin, GST_RTCP_SDES_NAME,
1661
 
          g_value_get_string (value));
1662
 
      break;
1663
 
    case PROP_SDES_EMAIL:
1664
 
      gst_rtp_bin_set_sdes_string (rtpbin, GST_RTCP_SDES_EMAIL,
1665
 
          g_value_get_string (value));
1666
 
      break;
1667
 
    case PROP_SDES_PHONE:
1668
 
      gst_rtp_bin_set_sdes_string (rtpbin, GST_RTCP_SDES_PHONE,
1669
 
          g_value_get_string (value));
1670
 
      break;
1671
 
    case PROP_SDES_LOCATION:
1672
 
      gst_rtp_bin_set_sdes_string (rtpbin, GST_RTCP_SDES_LOC,
1673
 
          g_value_get_string (value));
1674
 
      break;
1675
 
    case PROP_SDES_TOOL:
1676
 
      gst_rtp_bin_set_sdes_string (rtpbin, GST_RTCP_SDES_TOOL,
1677
 
          g_value_get_string (value));
1678
 
      break;
1679
 
    case PROP_SDES_NOTE:
1680
 
      gst_rtp_bin_set_sdes_string (rtpbin, GST_RTCP_SDES_NOTE,
1681
 
          g_value_get_string (value));
1682
 
      break;
1683
 
    case PROP_DO_LOST:
1684
 
      GST_RTP_BIN_LOCK (rtpbin);
1685
 
      rtpbin->do_lost = g_value_get_boolean (value);
1686
 
      GST_RTP_BIN_UNLOCK (rtpbin);
1687
 
      gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin, "do-lost", value);
1688
 
      break;
1689
 
    default:
1690
 
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1691
 
      break;
1692
 
  }
1693
 
}
1694
 
 
1695
 
static void
1696
 
gst_rtp_bin_get_property (GObject * object, guint prop_id,
1697
 
    GValue * value, GParamSpec * pspec)
1698
 
{
1699
 
  GstRtpBin *rtpbin;
1700
 
 
1701
 
  rtpbin = GST_RTP_BIN (object);
1702
 
 
1703
 
  switch (prop_id) {
1704
 
    case PROP_LATENCY:
1705
 
      GST_RTP_BIN_LOCK (rtpbin);
1706
 
      g_value_set_uint (value, rtpbin->latency);
1707
 
      GST_RTP_BIN_UNLOCK (rtpbin);
1708
 
      break;
1709
 
    case PROP_SDES_CNAME:
1710
 
      g_value_take_string (value, gst_rtp_bin_get_sdes_string (rtpbin,
1711
 
              GST_RTCP_SDES_CNAME));
1712
 
      break;
1713
 
    case PROP_SDES_NAME:
1714
 
      g_value_take_string (value, gst_rtp_bin_get_sdes_string (rtpbin,
1715
 
              GST_RTCP_SDES_NAME));
1716
 
      break;
1717
 
    case PROP_SDES_EMAIL:
1718
 
      g_value_take_string (value, gst_rtp_bin_get_sdes_string (rtpbin,
1719
 
              GST_RTCP_SDES_EMAIL));
1720
 
      break;
1721
 
    case PROP_SDES_PHONE:
1722
 
      g_value_take_string (value, gst_rtp_bin_get_sdes_string (rtpbin,
1723
 
              GST_RTCP_SDES_PHONE));
1724
 
      break;
1725
 
    case PROP_SDES_LOCATION:
1726
 
      g_value_take_string (value, gst_rtp_bin_get_sdes_string (rtpbin,
1727
 
              GST_RTCP_SDES_LOC));
1728
 
      break;
1729
 
    case PROP_SDES_TOOL:
1730
 
      g_value_take_string (value, gst_rtp_bin_get_sdes_string (rtpbin,
1731
 
              GST_RTCP_SDES_TOOL));
1732
 
      break;
1733
 
    case PROP_SDES_NOTE:
1734
 
      g_value_take_string (value, gst_rtp_bin_get_sdes_string (rtpbin,
1735
 
              GST_RTCP_SDES_NOTE));
1736
 
      break;
1737
 
    case PROP_DO_LOST:
1738
 
      GST_RTP_BIN_LOCK (rtpbin);
1739
 
      g_value_set_boolean (value, rtpbin->do_lost);
1740
 
      GST_RTP_BIN_UNLOCK (rtpbin);
1741
 
      break;
1742
 
    default:
1743
 
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1744
 
      break;
1745
 
  }
1746
 
}
1747
 
 
1748
 
static void
1749
 
gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message)
1750
 
{
1751
 
  GstRtpBin *rtpbin;
1752
 
 
1753
 
  rtpbin = GST_RTP_BIN (bin);
1754
 
 
1755
 
  switch (GST_MESSAGE_TYPE (message)) {
1756
 
    case GST_MESSAGE_ELEMENT:
1757
 
    {
1758
 
      const GstStructure *s = gst_message_get_structure (message);
1759
 
 
1760
 
      /* we change the structure name and add the session ID to it */
1761
 
      if (gst_structure_has_name (s, "application/x-rtp-source-sdes")) {
1762
 
        GSList *walk;
1763
 
 
1764
 
        /* find the session, the message source has it */
1765
 
        for (walk = rtpbin->sessions; walk; walk = g_slist_next (walk)) {
1766
 
          GstRtpBinSession *sess = (GstRtpBinSession *) walk->data;
1767
 
 
1768
 
          /* if we found the session, change message. else we exit the loop and
1769
 
           * leave the message unchanged */
1770
 
          if (GST_OBJECT_CAST (sess->session) == GST_MESSAGE_SRC (message)) {
1771
 
            message = gst_message_make_writable (message);
1772
 
            s = gst_message_get_structure (message);
1773
 
 
1774
 
            gst_structure_set ((GstStructure *) s, "session", G_TYPE_UINT,
1775
 
                sess->id, NULL);
1776
 
            break;
1777
 
          }
1778
 
        }
1779
 
      }
1780
 
      /* fallthrough to forward the modified message to the parent */
1781
 
    }
1782
 
    default:
1783
 
    {
1784
 
      GST_BIN_CLASS (parent_class)->handle_message (bin, message);
1785
 
      break;
1786
 
    }
1787
 
  }
1788
 
}
1789
 
 
1790
 
static void
1791
 
calc_ntp_ns_base (GstRtpBin * bin)
1792
 
{
1793
 
  GstClockTime now;
1794
 
  GTimeVal current;
1795
 
  GSList *walk;
1796
 
 
1797
 
  /* get the current time and convert it to NTP time in nanoseconds */
1798
 
  g_get_current_time (&current);
1799
 
  now = GST_TIMEVAL_TO_TIME (current);
1800
 
  now += (2208988800LL * GST_SECOND);
1801
 
 
1802
 
  GST_RTP_BIN_LOCK (bin);
1803
 
  bin->priv->ntp_ns_base = now;
1804
 
  for (walk = bin->sessions; walk; walk = g_slist_next (walk)) {
1805
 
    GstRtpBinSession *session = (GstRtpBinSession *) walk->data;
1806
 
 
1807
 
    g_object_set (session->session, "ntp-ns-base", now, NULL);
1808
 
  }
1809
 
  GST_RTP_BIN_UNLOCK (bin);
1810
 
 
1811
 
  return;
1812
 
}
1813
 
 
1814
 
static GstStateChangeReturn
1815
 
gst_rtp_bin_change_state (GstElement * element, GstStateChange transition)
1816
 
{
1817
 
  GstStateChangeReturn res;
1818
 
  GstRtpBin *rtpbin;
1819
 
  GstRtpBinPrivate *priv;
1820
 
 
1821
 
  rtpbin = GST_RTP_BIN (element);
1822
 
  priv = rtpbin->priv;
1823
 
 
1824
 
  switch (transition) {
1825
 
    case GST_STATE_CHANGE_NULL_TO_READY:
1826
 
      break;
1827
 
    case GST_STATE_CHANGE_READY_TO_PAUSED:
1828
 
      GST_LOG_OBJECT (rtpbin, "clearing shutdown flag");
1829
 
      g_atomic_int_set (&priv->shutdown, 0);
1830
 
      break;
1831
 
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1832
 
      calc_ntp_ns_base (rtpbin);
1833
 
      break;
1834
 
    case GST_STATE_CHANGE_PAUSED_TO_READY:
1835
 
      GST_LOG_OBJECT (rtpbin, "setting shutdown flag");
1836
 
      g_atomic_int_set (&priv->shutdown, 1);
1837
 
      /* wait for all callbacks to end by taking the lock. No new callbacks will
1838
 
       * be able to happen as we set the shutdown flag. */
1839
 
      GST_RTP_BIN_DYN_LOCK (rtpbin);
1840
 
      GST_LOG_OBJECT (rtpbin, "dynamic lock taken, we can continue shutdown");
1841
 
      GST_RTP_BIN_DYN_UNLOCK (rtpbin);
1842
 
      break;
1843
 
    default:
1844
 
      break;
1845
 
  }
1846
 
 
1847
 
  res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1848
 
 
1849
 
  switch (transition) {
1850
 
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1851
 
      break;
1852
 
    case GST_STATE_CHANGE_PAUSED_TO_READY:
1853
 
      break;
1854
 
    case GST_STATE_CHANGE_READY_TO_NULL:
1855
 
      break;
1856
 
    default:
1857
 
      break;
1858
 
  }
1859
 
  return res;
1860
 
}
1861
 
 
1862
 
/* a new pad (SSRC) was created in @session. This signal is emited from the
1863
 
 * payload demuxer. */
1864
 
static void
1865
 
new_payload_found (GstElement * element, guint pt, GstPad * pad,
1866
 
    GstRtpBinStream * stream)
1867
 
{
1868
 
  GstRtpBin *rtpbin;
1869
 
  GstElementClass *klass;
1870
 
  GstPadTemplate *templ;
1871
 
  gchar *padname;
1872
 
  GstPad *gpad;
1873
 
 
1874
 
  rtpbin = stream->bin;
1875
 
 
1876
 
  GST_DEBUG ("new payload pad %d", pt);
1877
 
 
1878
 
  GST_RTP_BIN_SHUTDOWN_LOCK (rtpbin, shutdown);
1879
 
 
1880
 
  /* ghost the pad to the parent */
1881
 
  klass = GST_ELEMENT_GET_CLASS (rtpbin);
1882
 
  templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%d_%d_%d");
1883
 
  padname = g_strdup_printf ("recv_rtp_src_%d_%u_%d",
1884
 
      stream->session->id, stream->ssrc, pt);
1885
 
  gpad = gst_ghost_pad_new_from_template (padname, pad, templ);
1886
 
  g_free (padname);
1887
 
 
1888
 
  gst_pad_set_caps (gpad, GST_PAD_CAPS (pad));
1889
 
  gst_pad_set_active (gpad, TRUE);
1890
 
  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), gpad);
1891
 
 
1892
 
  stream->pads = g_slist_prepend (stream->pads, gpad);
1893
 
 
1894
 
  GST_RTP_BIN_SHUTDOWN_UNLOCK (rtpbin);
1895
 
 
1896
 
  return;
1897
 
 
1898
 
shutdown:
1899
 
  {
1900
 
    GST_DEBUG ("ignoring, we are shutting down");
1901
 
    return;
1902
 
  }
1903
 
}
1904
 
 
1905
 
static GstCaps *
1906
 
pt_map_requested (GstElement * element, guint pt, GstRtpBinSession * session)
1907
 
{
1908
 
  GstRtpBin *rtpbin;
1909
 
  GstCaps *caps;
1910
 
 
1911
 
  rtpbin = session->bin;
1912
 
 
1913
 
  GST_DEBUG_OBJECT (rtpbin, "payload map requested for pt %d in session %d", pt,
1914
 
      session->id);
1915
 
 
1916
 
  caps = get_pt_map (session, pt);
1917
 
  if (!caps)
1918
 
    goto no_caps;
1919
 
 
1920
 
  return caps;
1921
 
 
1922
 
  /* ERRORS */
1923
 
no_caps:
1924
 
  {
1925
 
    GST_DEBUG_OBJECT (rtpbin, "could not get caps");
1926
 
    return NULL;
1927
 
  }
1928
 
}
1929
 
 
1930
 
/* emited when caps changed for the session */
1931
 
static void
1932
 
caps_changed (GstPad * pad, GParamSpec * pspec, GstRtpBinSession * session)
1933
 
{
1934
 
  GstRtpBin *bin;
1935
 
  GstCaps *caps;
1936
 
  gint payload;
1937
 
  const GstStructure *s;
1938
 
 
1939
 
  bin = session->bin;
1940
 
 
1941
 
  g_object_get (pad, "caps", &caps, NULL);
1942
 
 
1943
 
  if (caps == NULL)
1944
 
    return;
1945
 
 
1946
 
  GST_DEBUG_OBJECT (bin, "got caps %" GST_PTR_FORMAT, caps);
1947
 
 
1948
 
  s = gst_caps_get_structure (caps, 0);
1949
 
 
1950
 
  /* get payload, finish when it's not there */
1951
 
  if (!gst_structure_get_int (s, "payload", &payload))
1952
 
    return;
1953
 
 
1954
 
  GST_RTP_SESSION_LOCK (session);
1955
 
  GST_DEBUG_OBJECT (bin, "insert caps for payload %d", payload);
1956
 
  g_hash_table_insert (session->ptmap, GINT_TO_POINTER (payload), caps);
1957
 
  GST_RTP_SESSION_UNLOCK (session);
1958
 
}
1959
 
 
1960
 
/* a new pad (SSRC) was created in @session */
1961
 
static void
1962
 
new_ssrc_pad_found (GstElement * element, guint ssrc, GstPad * pad,
1963
 
    GstRtpBinSession * session)
1964
 
{
1965
 
  GstRtpBin *rtpbin;
1966
 
  GstRtpBinStream *stream;
1967
 
  GstPad *sinkpad, *srcpad;
1968
 
  gchar *padname;
1969
 
 
1970
 
  rtpbin = session->bin;
1971
 
 
1972
 
  GST_DEBUG_OBJECT (rtpbin, "new SSRC pad %08x, %s:%s", ssrc,
1973
 
      GST_DEBUG_PAD_NAME (pad));
1974
 
 
1975
 
  GST_RTP_BIN_SHUTDOWN_LOCK (rtpbin, shutdown);
1976
 
 
1977
 
  GST_RTP_SESSION_LOCK (session);
1978
 
 
1979
 
  /* create new stream */
1980
 
  stream = create_stream (session, ssrc);
1981
 
  if (!stream)
1982
 
    goto no_stream;
1983
 
 
1984
 
  /* get pad and link */
1985
 
  GST_DEBUG_OBJECT (rtpbin, "linking jitterbuffer RTP");
1986
 
  padname = g_strdup_printf ("src_%d", ssrc);
1987
 
  srcpad = gst_element_get_static_pad (element, padname);
1988
 
  g_free (padname);
1989
 
  sinkpad = gst_element_get_static_pad (stream->buffer, "sink");
1990
 
  gst_pad_link (srcpad, sinkpad);
1991
 
  gst_object_unref (sinkpad);
1992
 
  gst_object_unref (srcpad);
1993
 
 
1994
 
  GST_DEBUG_OBJECT (rtpbin, "linking jitterbuffer RTCP");
1995
 
  padname = g_strdup_printf ("rtcp_src_%d", ssrc);
1996
 
  srcpad = gst_element_get_static_pad (element, padname);
1997
 
  g_free (padname);
1998
 
  sinkpad = gst_element_get_request_pad (stream->buffer, "sink_rtcp");
1999
 
  gst_pad_link (srcpad, sinkpad);
2000
 
  gst_object_unref (sinkpad);
2001
 
  gst_object_unref (srcpad);
2002
 
 
2003
 
  /* connect to the RTCP sync signal from the jitterbuffer */
2004
 
  GST_DEBUG_OBJECT (rtpbin, "connecting sync signal");
2005
 
  stream->buffer_handlesync_sig = g_signal_connect (stream->buffer,
2006
 
      "handle-sync", (GCallback) gst_rtp_bin_handle_sync, stream);
2007
 
 
2008
 
  /* connect to the new-pad signal of the payload demuxer, this will expose the
2009
 
   * new pad by ghosting it. */
2010
 
  stream->demux_newpad_sig = g_signal_connect (stream->demux,
2011
 
      "new-payload-type", (GCallback) new_payload_found, stream);
2012
 
  /* connect to the request-pt-map signal. This signal will be emited by the
2013
 
   * demuxer so that it can apply a proper caps on the buffers for the
2014
 
   * depayloaders. */
2015
 
  stream->demux_ptreq_sig = g_signal_connect (stream->demux,
2016
 
      "request-pt-map", (GCallback) pt_map_requested, session);
2017
 
 
2018
 
  GST_RTP_SESSION_UNLOCK (session);
2019
 
  GST_RTP_BIN_SHUTDOWN_UNLOCK (rtpbin);
2020
 
 
2021
 
  return;
2022
 
 
2023
 
  /* ERRORS */
2024
 
shutdown:
2025
 
  {
2026
 
    GST_DEBUG_OBJECT (rtpbin, "we are shutting down");
2027
 
    return;
2028
 
  }
2029
 
no_stream:
2030
 
  {
2031
 
    GST_RTP_SESSION_UNLOCK (session);
2032
 
    GST_RTP_BIN_SHUTDOWN_UNLOCK (rtpbin);
2033
 
    GST_DEBUG_OBJECT (rtpbin, "could not create stream");
2034
 
    return;
2035
 
  }
2036
 
}
2037
 
 
2038
 
/* Create a pad for receiving RTP for the session in @name. Must be called with
2039
 
 * RTP_BIN_LOCK.
2040
 
 */
2041
 
static GstPad *
2042
 
create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
2043
 
{
2044
 
  GstPad *sinkdpad;
2045
 
  guint sessid;
2046
 
  GstRtpBinSession *session;
2047
 
  GstPadLinkReturn lres;
2048
 
 
2049
 
  /* first get the session number */
2050
 
  if (name == NULL || sscanf (name, "recv_rtp_sink_%d", &sessid) != 1)
2051
 
    goto no_name;
2052
 
 
2053
 
  GST_DEBUG_OBJECT (rtpbin, "finding session %d", sessid);
2054
 
 
2055
 
  /* get or create session */
2056
 
  session = find_session_by_id (rtpbin, sessid);
2057
 
  if (!session) {
2058
 
    GST_DEBUG_OBJECT (rtpbin, "creating session %d", sessid);
2059
 
    /* create session now */
2060
 
    session = create_session (rtpbin, sessid);
2061
 
    if (session == NULL)
2062
 
      goto create_error;
2063
 
  }
2064
 
 
2065
 
  /* check if pad was requested */
2066
 
  if (session->recv_rtp_sink_ghost != NULL)
2067
 
    return session->recv_rtp_sink_ghost;
2068
 
 
2069
 
  GST_DEBUG_OBJECT (rtpbin, "getting RTP sink pad");
2070
 
  /* get recv_rtp pad and store */
2071
 
  session->recv_rtp_sink =
2072
 
      gst_element_get_request_pad (session->session, "recv_rtp_sink");
2073
 
  if (session->recv_rtp_sink == NULL)
2074
 
    goto pad_failed;
2075
 
 
2076
 
  g_signal_connect (session->recv_rtp_sink, "notify::caps",
2077
 
      (GCallback) caps_changed, session);
2078
 
 
2079
 
  GST_DEBUG_OBJECT (rtpbin, "getting RTP src pad");
2080
 
  /* get srcpad, link to SSRCDemux */
2081
 
  session->recv_rtp_src =
2082
 
      gst_element_get_static_pad (session->session, "recv_rtp_src");
2083
 
  if (session->recv_rtp_src == NULL)
2084
 
    goto pad_failed;
2085
 
 
2086
 
  GST_DEBUG_OBJECT (rtpbin, "getting demuxer RTP sink pad");
2087
 
  sinkdpad = gst_element_get_static_pad (session->demux, "sink");
2088
 
  GST_DEBUG_OBJECT (rtpbin, "linking demuxer RTP sink pad");
2089
 
  lres = gst_pad_link (session->recv_rtp_src, sinkdpad);
2090
 
  gst_object_unref (sinkdpad);
2091
 
  if (lres != GST_PAD_LINK_OK)
2092
 
    goto link_failed;
2093
 
 
2094
 
  /* connect to the new-ssrc-pad signal of the SSRC demuxer */
2095
 
  session->demux_newpad_sig = g_signal_connect (session->demux,
2096
 
      "new-ssrc-pad", (GCallback) new_ssrc_pad_found, session);
2097
 
  session->demux_padremoved_sig = g_signal_connect (session->demux,
2098
 
      "removed-ssrc-pad", (GCallback) ssrc_demux_pad_removed, session);
2099
 
 
2100
 
  GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad");
2101
 
  session->recv_rtp_sink_ghost =
2102
 
      gst_ghost_pad_new_from_template (name, session->recv_rtp_sink, templ);
2103
 
  gst_pad_set_active (session->recv_rtp_sink_ghost, TRUE);
2104
 
  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->recv_rtp_sink_ghost);
2105
 
 
2106
 
  return session->recv_rtp_sink_ghost;
2107
 
 
2108
 
  /* ERRORS */
2109
 
no_name:
2110
 
  {
2111
 
    g_warning ("gstrtpbin: invalid name given");
2112
 
    return NULL;
2113
 
  }
2114
 
create_error:
2115
 
  {
2116
 
    /* create_session already warned */
2117
 
    return NULL;
2118
 
  }
2119
 
pad_failed:
2120
 
  {
2121
 
    g_warning ("gstrtpbin: failed to get session pad");
2122
 
    return NULL;
2123
 
  }
2124
 
link_failed:
2125
 
  {
2126
 
    g_warning ("gstrtpbin: failed to link pads");
2127
 
    return NULL;
2128
 
  }
2129
 
}
2130
 
 
2131
 
static void
2132
 
remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
2133
 
{
2134
 
  if (session->demux_newpad_sig) {
2135
 
    g_signal_handler_disconnect (session->demux, session->demux_newpad_sig);
2136
 
    session->demux_newpad_sig = 0;
2137
 
  }
2138
 
  if (session->demux_padremoved_sig) {
2139
 
    g_signal_handler_disconnect (session->demux, session->demux_padremoved_sig);
2140
 
    session->demux_padremoved_sig = 0;
2141
 
  }
2142
 
  if (session->recv_rtp_src) {
2143
 
    gst_object_unref (session->recv_rtp_src);
2144
 
    session->recv_rtp_src = NULL;
2145
 
  }
2146
 
  if (session->recv_rtp_sink) {
2147
 
    gst_element_release_request_pad (session->session, session->recv_rtp_sink);
2148
 
    gst_object_unref (session->recv_rtp_sink);
2149
 
    session->recv_rtp_sink = NULL;
2150
 
  }
2151
 
  if (session->recv_rtp_sink_ghost) {
2152
 
    gst_pad_set_active (session->recv_rtp_sink_ghost, FALSE);
2153
 
    gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
2154
 
        session->recv_rtp_sink_ghost);
2155
 
    session->recv_rtp_sink_ghost = NULL;
2156
 
  }
2157
 
}
2158
 
 
2159
 
/* Create a pad for receiving RTCP for the session in @name. Must be called with
2160
 
 * RTP_BIN_LOCK.
2161
 
 */
2162
 
static GstPad *
2163
 
create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
2164
 
    const gchar * name)
2165
 
{
2166
 
  guint sessid;
2167
 
  GstRtpBinSession *session;
2168
 
  GstPad *sinkdpad;
2169
 
  GstPadLinkReturn lres;
2170
 
 
2171
 
  /* first get the session number */
2172
 
  if (name == NULL || sscanf (name, "recv_rtcp_sink_%d", &sessid) != 1)
2173
 
    goto no_name;
2174
 
 
2175
 
  GST_DEBUG_OBJECT (rtpbin, "finding session %d", sessid);
2176
 
 
2177
 
  /* get or create the session */
2178
 
  session = find_session_by_id (rtpbin, sessid);
2179
 
  if (!session) {
2180
 
    GST_DEBUG_OBJECT (rtpbin, "creating session %d", sessid);
2181
 
    /* create session now */
2182
 
    session = create_session (rtpbin, sessid);
2183
 
    if (session == NULL)
2184
 
      goto create_error;
2185
 
  }
2186
 
 
2187
 
  /* check if pad was requested */
2188
 
  if (session->recv_rtcp_sink_ghost != NULL)
2189
 
    return session->recv_rtcp_sink_ghost;
2190
 
 
2191
 
  /* get recv_rtp pad and store */
2192
 
  GST_DEBUG_OBJECT (rtpbin, "getting RTCP sink pad");
2193
 
  session->recv_rtcp_sink =
2194
 
      gst_element_get_request_pad (session->session, "recv_rtcp_sink");
2195
 
  if (session->recv_rtcp_sink == NULL)
2196
 
    goto pad_failed;
2197
 
 
2198
 
  /* get srcpad, link to SSRCDemux */
2199
 
  GST_DEBUG_OBJECT (rtpbin, "getting sync src pad");
2200
 
  session->sync_src = gst_element_get_static_pad (session->session, "sync_src");
2201
 
  if (session->sync_src == NULL)
2202
 
    goto pad_failed;
2203
 
 
2204
 
  GST_DEBUG_OBJECT (rtpbin, "getting demuxer RTCP sink pad");
2205
 
  sinkdpad = gst_element_get_static_pad (session->demux, "rtcp_sink");
2206
 
  lres = gst_pad_link (session->sync_src, sinkdpad);
2207
 
  gst_object_unref (sinkdpad);
2208
 
  if (lres != GST_PAD_LINK_OK)
2209
 
    goto link_failed;
2210
 
 
2211
 
  session->recv_rtcp_sink_ghost =
2212
 
      gst_ghost_pad_new_from_template (name, session->recv_rtcp_sink, templ);
2213
 
  gst_pad_set_active (session->recv_rtcp_sink_ghost, TRUE);
2214
 
  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin),
2215
 
      session->recv_rtcp_sink_ghost);
2216
 
 
2217
 
  return session->recv_rtcp_sink_ghost;
2218
 
 
2219
 
  /* ERRORS */
2220
 
no_name:
2221
 
  {
2222
 
    g_warning ("gstrtpbin: invalid name given");
2223
 
    return NULL;
2224
 
  }
2225
 
create_error:
2226
 
  {
2227
 
    /* create_session already warned */
2228
 
    return NULL;
2229
 
  }
2230
 
pad_failed:
2231
 
  {
2232
 
    g_warning ("gstrtpbin: failed to get session pad");
2233
 
    return NULL;
2234
 
  }
2235
 
link_failed:
2236
 
  {
2237
 
    g_warning ("gstrtpbin: failed to link pads");
2238
 
    return NULL;
2239
 
  }
2240
 
}
2241
 
 
2242
 
static void
2243
 
remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session)
2244
 
{
2245
 
  if (session->recv_rtcp_sink_ghost) {
2246
 
    gst_pad_set_active (session->recv_rtcp_sink_ghost, FALSE);
2247
 
    gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
2248
 
        session->recv_rtcp_sink_ghost);
2249
 
    session->recv_rtcp_sink_ghost = NULL;
2250
 
  }
2251
 
  if (session->sync_src) {
2252
 
    /* releasing the request pad should also unref the sync pad */
2253
 
    gst_object_unref (session->sync_src);
2254
 
    session->sync_src = NULL;
2255
 
  }
2256
 
  if (session->recv_rtcp_sink) {
2257
 
    gst_element_release_request_pad (session->session, session->recv_rtcp_sink);
2258
 
    gst_object_unref (session->recv_rtcp_sink);
2259
 
    session->recv_rtcp_sink = NULL;
2260
 
  }
2261
 
}
2262
 
 
2263
 
/* Create a pad for sending RTP for the session in @name. Must be called with
2264
 
 * RTP_BIN_LOCK.
2265
 
 */
2266
 
static GstPad *
2267
 
create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
2268
 
{
2269
 
  gchar *gname;
2270
 
  guint sessid;
2271
 
  GstRtpBinSession *session;
2272
 
  GstElementClass *klass;
2273
 
 
2274
 
  /* first get the session number */
2275
 
  if (name == NULL || sscanf (name, "send_rtp_sink_%d", &sessid) != 1)
2276
 
    goto no_name;
2277
 
 
2278
 
  /* get or create session */
2279
 
  session = find_session_by_id (rtpbin, sessid);
2280
 
  if (!session) {
2281
 
    /* create session now */
2282
 
    session = create_session (rtpbin, sessid);
2283
 
    if (session == NULL)
2284
 
      goto create_error;
2285
 
  }
2286
 
 
2287
 
  /* check if pad was requested */
2288
 
  if (session->send_rtp_sink_ghost != NULL)
2289
 
    return session->send_rtp_sink_ghost;
2290
 
 
2291
 
  /* get send_rtp pad and store */
2292
 
  session->send_rtp_sink =
2293
 
      gst_element_get_request_pad (session->session, "send_rtp_sink");
2294
 
  if (session->send_rtp_sink == NULL)
2295
 
    goto pad_failed;
2296
 
 
2297
 
  session->send_rtp_sink_ghost =
2298
 
      gst_ghost_pad_new_from_template (name, session->send_rtp_sink, templ);
2299
 
  gst_pad_set_active (session->send_rtp_sink_ghost, TRUE);
2300
 
  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtp_sink_ghost);
2301
 
 
2302
 
  /* get srcpad */
2303
 
  session->send_rtp_src =
2304
 
      gst_element_get_static_pad (session->session, "send_rtp_src");
2305
 
  if (session->send_rtp_src == NULL)
2306
 
    goto no_srcpad;
2307
 
 
2308
 
  /* ghost the new source pad */
2309
 
  klass = GST_ELEMENT_GET_CLASS (rtpbin);
2310
 
  gname = g_strdup_printf ("send_rtp_src_%d", sessid);
2311
 
  templ = gst_element_class_get_pad_template (klass, "send_rtp_src_%d");
2312
 
  session->send_rtp_src_ghost =
2313
 
      gst_ghost_pad_new_from_template (gname, session->send_rtp_src, templ);
2314
 
  gst_pad_set_active (session->send_rtp_src_ghost, TRUE);
2315
 
  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtp_src_ghost);
2316
 
  g_free (gname);
2317
 
 
2318
 
  return session->send_rtp_sink_ghost;
2319
 
 
2320
 
  /* ERRORS */
2321
 
no_name:
2322
 
  {
2323
 
    g_warning ("gstrtpbin: invalid name given");
2324
 
    return NULL;
2325
 
  }
2326
 
create_error:
2327
 
  {
2328
 
    /* create_session already warned */
2329
 
    return NULL;
2330
 
  }
2331
 
pad_failed:
2332
 
  {
2333
 
    g_warning ("gstrtpbin: failed to get session pad for session %d", sessid);
2334
 
    return NULL;
2335
 
  }
2336
 
no_srcpad:
2337
 
  {
2338
 
    g_warning ("gstrtpbin: failed to get rtp source pad for session %d",
2339
 
        sessid);
2340
 
    return NULL;
2341
 
  }
2342
 
}
2343
 
 
2344
 
static void
2345
 
remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
2346
 
{
2347
 
  if (session->send_rtp_src_ghost) {
2348
 
    gst_pad_set_active (session->send_rtp_src_ghost, FALSE);
2349
 
    gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
2350
 
        session->send_rtp_src_ghost);
2351
 
    session->send_rtp_src_ghost = NULL;
2352
 
  }
2353
 
  if (session->send_rtp_src) {
2354
 
    gst_object_unref (session->send_rtp_src);
2355
 
    session->send_rtp_src = NULL;
2356
 
  }
2357
 
  if (session->send_rtp_sink) {
2358
 
    gst_element_release_request_pad (GST_ELEMENT_CAST (session->session),
2359
 
        session->send_rtp_sink);
2360
 
    gst_object_unref (session->send_rtp_sink);
2361
 
    session->send_rtp_sink = NULL;
2362
 
  }
2363
 
  if (session->send_rtp_sink_ghost) {
2364
 
    gst_pad_set_active (session->send_rtp_sink_ghost, FALSE);
2365
 
    gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
2366
 
        session->send_rtp_sink_ghost);
2367
 
    session->send_rtp_sink_ghost = NULL;
2368
 
  }
2369
 
}
2370
 
 
2371
 
/* Create a pad for sending RTCP for the session in @name. Must be called with
2372
 
 * RTP_BIN_LOCK.
2373
 
 */
2374
 
static GstPad *
2375
 
create_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
2376
 
{
2377
 
  guint sessid;
2378
 
  GstRtpBinSession *session;
2379
 
 
2380
 
  /* first get the session number */
2381
 
  if (name == NULL || sscanf (name, "send_rtcp_src_%d", &sessid) != 1)
2382
 
    goto no_name;
2383
 
 
2384
 
  /* get or create session */
2385
 
  session = find_session_by_id (rtpbin, sessid);
2386
 
  if (!session)
2387
 
    goto no_session;
2388
 
 
2389
 
  /* check if pad was requested */
2390
 
  if (session->send_rtcp_src_ghost != NULL)
2391
 
    return session->send_rtcp_src_ghost;
2392
 
 
2393
 
  /* get rtcp_src pad and store */
2394
 
  session->send_rtcp_src =
2395
 
      gst_element_get_request_pad (session->session, "send_rtcp_src");
2396
 
  if (session->send_rtcp_src == NULL)
2397
 
    goto pad_failed;
2398
 
 
2399
 
  session->send_rtcp_src_ghost =
2400
 
      gst_ghost_pad_new_from_template (name, session->send_rtcp_src, templ);
2401
 
  gst_pad_set_active (session->send_rtcp_src_ghost, TRUE);
2402
 
  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtcp_src_ghost);
2403
 
 
2404
 
  return session->send_rtcp_src_ghost;
2405
 
 
2406
 
  /* ERRORS */
2407
 
no_name:
2408
 
  {
2409
 
    g_warning ("gstrtpbin: invalid name given");
2410
 
    return NULL;
2411
 
  }
2412
 
no_session:
2413
 
  {
2414
 
    g_warning ("gstrtpbin: session with id %d does not exist", sessid);
2415
 
    return NULL;
2416
 
  }
2417
 
pad_failed:
2418
 
  {
2419
 
    g_warning ("gstrtpbin: failed to get rtcp pad for session %d", sessid);
2420
 
    return NULL;
2421
 
  }
2422
 
}
2423
 
 
2424
 
static void
2425
 
remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session)
2426
 
{
2427
 
  if (session->send_rtcp_src_ghost) {
2428
 
    gst_pad_set_active (session->send_rtcp_src_ghost, FALSE);
2429
 
    gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
2430
 
        session->send_rtcp_src_ghost);
2431
 
    session->send_rtcp_src_ghost = NULL;
2432
 
  }
2433
 
  if (session->send_rtcp_src) {
2434
 
    gst_element_release_request_pad (session->session, session->send_rtcp_src);
2435
 
    gst_object_unref (session->send_rtcp_src);
2436
 
    session->send_rtcp_src = NULL;
2437
 
  }
2438
 
}
2439
 
 
2440
 
/* If the requested name is NULL we should create a name with
2441
 
 * the session number assuming we want the lowest posible session
2442
 
 * with a free pad like the template */
2443
 
static gchar *
2444
 
gst_rtp_bin_get_free_pad_name (GstElement * element, GstPadTemplate * templ)
2445
 
{
2446
 
  gboolean name_found = FALSE;
2447
 
  gint session = 0;
2448
 
  GstPad *pad = NULL;
2449
 
  GstIterator *pad_it = NULL;
2450
 
  gchar *pad_name = NULL;
2451
 
 
2452
 
  GST_DEBUG_OBJECT (element, "find a free pad name for template");
2453
 
  while (!name_found) {
2454
 
    g_free (pad_name);
2455
 
    pad_name = g_strdup_printf (templ->name_template, session++);
2456
 
    pad_it = gst_element_iterate_pads (GST_ELEMENT (element));
2457
 
    name_found = TRUE;
2458
 
    while (gst_iterator_next (pad_it, (gpointer) & pad) == GST_ITERATOR_OK) {
2459
 
      gchar *name;
2460
 
 
2461
 
      name = gst_pad_get_name (pad);
2462
 
      if (strcmp (name, pad_name) == 0)
2463
 
        name_found = FALSE;
2464
 
      g_free (name);
2465
 
    }
2466
 
    gst_iterator_free (pad_it);
2467
 
  }
2468
 
 
2469
 
  GST_DEBUG_OBJECT (element, "free pad name found: '%s'", pad_name);
2470
 
  return pad_name;
2471
 
}
2472
 
 
2473
 
/* 
2474
 
 */
2475
 
static GstPad *
2476
 
gst_rtp_bin_request_new_pad (GstElement * element,
2477
 
    GstPadTemplate * templ, const gchar * name)
2478
 
{
2479
 
  GstRtpBin *rtpbin;
2480
 
  GstElementClass *klass;
2481
 
  GstPad *result;
2482
 
 
2483
 
  gchar *pad_name = NULL;
2484
 
 
2485
 
  g_return_val_if_fail (templ != NULL, NULL);
2486
 
  g_return_val_if_fail (GST_IS_RTP_BIN (element), NULL);
2487
 
 
2488
 
  rtpbin = GST_RTP_BIN (element);
2489
 
  klass = GST_ELEMENT_GET_CLASS (element);
2490
 
 
2491
 
  GST_RTP_BIN_LOCK (rtpbin);
2492
 
 
2493
 
  if (name == NULL) {
2494
 
    /* use a free pad name */
2495
 
    pad_name = gst_rtp_bin_get_free_pad_name (element, templ);
2496
 
  } else {
2497
 
    /* use the provided name */
2498
 
    pad_name = g_strdup (name);
2499
 
  }
2500
 
 
2501
 
  GST_DEBUG_OBJECT (rtpbin, "Trying to request a pad with name %s", pad_name);
2502
 
 
2503
 
  /* figure out the template */
2504
 
  if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%d")) {
2505
 
    result = create_recv_rtp (rtpbin, templ, pad_name);
2506
 
  } else if (templ == gst_element_class_get_pad_template (klass,
2507
 
          "recv_rtcp_sink_%d")) {
2508
 
    result = create_recv_rtcp (rtpbin, templ, pad_name);
2509
 
  } else if (templ == gst_element_class_get_pad_template (klass,
2510
 
          "send_rtp_sink_%d")) {
2511
 
    result = create_send_rtp (rtpbin, templ, pad_name);
2512
 
  } else if (templ == gst_element_class_get_pad_template (klass,
2513
 
          "send_rtcp_src_%d")) {
2514
 
    result = create_rtcp (rtpbin, templ, pad_name);
2515
 
  } else
2516
 
    goto wrong_template;
2517
 
 
2518
 
  g_free (pad_name);
2519
 
  GST_RTP_BIN_UNLOCK (rtpbin);
2520
 
 
2521
 
  return result;
2522
 
 
2523
 
  /* ERRORS */
2524
 
wrong_template:
2525
 
  {
2526
 
    g_free (pad_name);
2527
 
    GST_RTP_BIN_UNLOCK (rtpbin);
2528
 
    g_warning ("gstrtpbin: this is not our template");
2529
 
    return NULL;
2530
 
  }
2531
 
}
2532
 
 
2533
 
static void
2534
 
gst_rtp_bin_release_pad (GstElement * element, GstPad * pad)
2535
 
{
2536
 
  GstRtpBinSession *session;
2537
 
  GstRtpBin *rtpbin;
2538
 
 
2539
 
  g_return_if_fail (GST_IS_GHOST_PAD (pad));
2540
 
  g_return_if_fail (GST_IS_RTP_BIN (element));
2541
 
 
2542
 
  rtpbin = GST_RTP_BIN (element);
2543
 
 
2544
 
  GST_RTP_BIN_LOCK (rtpbin);
2545
 
  GST_DEBUG_OBJECT (rtpbin, "Trying to release pad %s:%s",
2546
 
      GST_DEBUG_PAD_NAME (pad));
2547
 
 
2548
 
  if (!(session = find_session_by_pad (rtpbin, pad)))
2549
 
    goto unknown_pad;
2550
 
 
2551
 
  if (session->recv_rtp_sink_ghost == pad) {
2552
 
    remove_recv_rtp (rtpbin, session);
2553
 
  } else if (session->recv_rtcp_sink_ghost == pad) {
2554
 
    remove_recv_rtcp (rtpbin, session);
2555
 
  } else if (session->send_rtp_sink_ghost == pad) {
2556
 
    remove_send_rtp (rtpbin, session);
2557
 
  } else if (session->send_rtcp_src_ghost == pad) {
2558
 
    remove_rtcp (rtpbin, session);
2559
 
  }
2560
 
 
2561
 
  /* no more request pads, free the complete session */
2562
 
  if (session->recv_rtp_sink_ghost == NULL
2563
 
      && session->recv_rtcp_sink_ghost == NULL
2564
 
      && session->send_rtp_sink_ghost == NULL
2565
 
      && session->send_rtcp_src_ghost == NULL) {
2566
 
    GST_DEBUG_OBJECT (rtpbin, "no more pads for session %p", session);
2567
 
    rtpbin->sessions = g_slist_remove (rtpbin->sessions, session);
2568
 
    free_session (session, rtpbin);
2569
 
  }
2570
 
  GST_RTP_BIN_UNLOCK (rtpbin);
2571
 
 
2572
 
  return;
2573
 
 
2574
 
  /* ERROR */
2575
 
unknown_pad:
2576
 
  {
2577
 
    GST_RTP_BIN_UNLOCK (rtpbin);
2578
 
    g_warning ("gstrtpbin: %s:%s is not one of our request pads",
2579
 
        GST_DEBUG_PAD_NAME (pad));
2580
 
    return;
2581
 
  }
2582
 
}