Blame gst/rtsp/gstrtpdec.c

Packit 1f69a5
/* GStreamer
Packit 1f69a5
 * Copyright (C) <2005,2006> Wim Taymans <wim.taymans@gmail.com>
Packit 1f69a5
 *
Packit 1f69a5
 * This library is free software; you can redistribute it and/or
Packit 1f69a5
 * modify it under the terms of the GNU Library General Public
Packit 1f69a5
 * License as published by the Free Software Foundation; either
Packit 1f69a5
 * version 2 of the License, or (at your option) any later version.
Packit 1f69a5
 *
Packit 1f69a5
 * This library is distributed in the hope that it will be useful,
Packit 1f69a5
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 1f69a5
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 1f69a5
 * Library General Public License for more details.
Packit 1f69a5
 *
Packit 1f69a5
 * You should have received a copy of the GNU Library General Public
Packit 1f69a5
 * License along with this library; if not, write to the
Packit 1f69a5
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 1f69a5
 * Boston, MA 02110-1301, USA.
Packit 1f69a5
 */
Packit 1f69a5
/*
Packit 1f69a5
 * Unless otherwise indicated, Source Code is licensed under MIT license.
Packit 1f69a5
 * See further explanation attached in License Statement (distributed in the file
Packit 1f69a5
 * LICENSE).
Packit 1f69a5
 *
Packit 1f69a5
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
Packit 1f69a5
 * this software and associated documentation files (the "Software"), to deal in
Packit 1f69a5
 * the Software without restriction, including without limitation the rights to
Packit 1f69a5
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
Packit 1f69a5
 * of the Software, and to permit persons to whom the Software is furnished to do
Packit 1f69a5
 * so, subject to the following conditions:
Packit 1f69a5
 *
Packit 1f69a5
 * The above copyright notice and this permission notice shall be included in all
Packit 1f69a5
 * copies or substantial portions of the Software.
Packit 1f69a5
 *
Packit 1f69a5
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit 1f69a5
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit 1f69a5
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit 1f69a5
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit 1f69a5
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Packit 1f69a5
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit 1f69a5
 * SOFTWARE.
Packit 1f69a5
 */
Packit 1f69a5
/* Element-Checklist-Version: 5 */
Packit 1f69a5
Packit 1f69a5
/**
Packit 1f69a5
 * SECTION:element-rtpdec
Packit 1f69a5
 *
Packit 1f69a5
 * A simple RTP session manager used internally by rtspsrc.
Packit 1f69a5
 */
Packit 1f69a5
Packit 1f69a5
/* #define HAVE_RTCP */
Packit 1f69a5
Packit 1f69a5
#include <gst/rtp/gstrtpbuffer.h>
Packit 1f69a5
Packit 1f69a5
#ifdef HAVE_RTCP
Packit 1f69a5
#include <gst/rtp/gstrtcpbuffer.h>
Packit 1f69a5
#endif
Packit 1f69a5
Packit 1f69a5
#include "gstrtpdec.h"
Packit 1f69a5
#include <stdio.h>
Packit 1f69a5
Packit 1f69a5
GST_DEBUG_CATEGORY_STATIC (rtpdec_debug);
Packit 1f69a5
#define GST_CAT_DEFAULT (rtpdec_debug)
Packit 1f69a5
Packit 1f69a5
/* GstRTPDec signals and args */
Packit 1f69a5
enum
Packit 1f69a5
{
Packit 1f69a5
  SIGNAL_REQUEST_PT_MAP,
Packit 1f69a5
  SIGNAL_CLEAR_PT_MAP,
Packit 1f69a5
Packit 1f69a5
  SIGNAL_ON_NEW_SSRC,
Packit 1f69a5
  SIGNAL_ON_SSRC_COLLISION,
Packit 1f69a5
  SIGNAL_ON_SSRC_VALIDATED,
Packit 1f69a5
  SIGNAL_ON_BYE_SSRC,
Packit 1f69a5
  SIGNAL_ON_BYE_TIMEOUT,
Packit 1f69a5
  SIGNAL_ON_TIMEOUT,
Packit 1f69a5
  LAST_SIGNAL
Packit 1f69a5
};
Packit 1f69a5
Packit 1f69a5
#define DEFAULT_LATENCY_MS      200
Packit 1f69a5
Packit 1f69a5
enum
Packit 1f69a5
{
Packit 1f69a5
  PROP_0,
Packit 1f69a5
  PROP_LATENCY
Packit 1f69a5
};
Packit 1f69a5
Packit 1f69a5
static GstStaticPadTemplate gst_rtp_dec_recv_rtp_sink_template =
Packit 1f69a5
GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%u",
Packit 1f69a5
    GST_PAD_SINK,
Packit 1f69a5
    GST_PAD_REQUEST,
Packit 1f69a5
    GST_STATIC_CAPS ("application/x-rtp")
Packit 1f69a5
    );
Packit 1f69a5
Packit 1f69a5
static GstStaticPadTemplate gst_rtp_dec_recv_rtcp_sink_template =
Packit 1f69a5
GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%u",
Packit 1f69a5
    GST_PAD_SINK,
Packit 1f69a5
    GST_PAD_REQUEST,
Packit 1f69a5
    GST_STATIC_CAPS ("application/x-rtcp")
Packit 1f69a5
    );
Packit 1f69a5
Packit 1f69a5
static GstStaticPadTemplate gst_rtp_dec_recv_rtp_src_template =
Packit 1f69a5
GST_STATIC_PAD_TEMPLATE ("recv_rtp_src_%u_%u_%u",
Packit 1f69a5
    GST_PAD_SRC,
Packit 1f69a5
    GST_PAD_SOMETIMES,
Packit 1f69a5
    GST_STATIC_CAPS ("application/x-rtp")
Packit 1f69a5
    );
Packit 1f69a5
Packit 1f69a5
static GstStaticPadTemplate gst_rtp_dec_rtcp_src_template =
Packit 1f69a5
GST_STATIC_PAD_TEMPLATE ("rtcp_src_%u",
Packit 1f69a5
    GST_PAD_SRC,
Packit 1f69a5
    GST_PAD_REQUEST,
Packit 1f69a5
    GST_STATIC_CAPS ("application/x-rtcp")
Packit 1f69a5
    );
Packit 1f69a5
Packit 1f69a5
static void gst_rtp_dec_finalize (GObject * object);
Packit 1f69a5
static void gst_rtp_dec_set_property (GObject * object,
Packit 1f69a5
    guint prop_id, const GValue * value, GParamSpec * pspec);
Packit 1f69a5
static void gst_rtp_dec_get_property (GObject * object,
Packit 1f69a5
    guint prop_id, GValue * value, GParamSpec * pspec);
Packit 1f69a5
Packit 1f69a5
static GstClock *gst_rtp_dec_provide_clock (GstElement * element);
Packit 1f69a5
static GstStateChangeReturn gst_rtp_dec_change_state (GstElement * element,
Packit 1f69a5
    GstStateChange transition);
Packit 1f69a5
static GstPad *gst_rtp_dec_request_new_pad (GstElement * element,
Packit 1f69a5
    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
Packit 1f69a5
static void gst_rtp_dec_release_pad (GstElement * element, GstPad * pad);
Packit 1f69a5
Packit 1f69a5
static GstFlowReturn gst_rtp_dec_chain_rtp (GstPad * pad, GstObject * parent,
Packit 1f69a5
    GstBuffer * buffer);
Packit 1f69a5
static GstFlowReturn gst_rtp_dec_chain_rtcp (GstPad * pad, GstObject * parent,
Packit 1f69a5
    GstBuffer * buffer);
Packit 1f69a5
Packit 1f69a5
Packit 1f69a5
/* Manages the receiving end of the packets.
Packit 1f69a5
 *
Packit 1f69a5
 * There is one such structure for each RTP session (audio/video/...).
Packit 1f69a5
 * We get the RTP/RTCP packets and stuff them into the session manager. 
Packit 1f69a5
 */
Packit 1f69a5
struct _GstRTPDecSession
Packit 1f69a5
{
Packit 1f69a5
  /* session id */
Packit 1f69a5
  gint id;
Packit 1f69a5
  /* the parent bin */
Packit 1f69a5
  GstRTPDec *dec;
Packit 1f69a5
Packit 1f69a5
  gboolean active;
Packit 1f69a5
  /* we only support one ssrc and one pt */
Packit 1f69a5
  guint32 ssrc;
Packit 1f69a5
  guint8 pt;
Packit 1f69a5
  GstCaps *caps;
Packit 1f69a5
Packit 1f69a5
  /* the pads of the session */
Packit 1f69a5
  GstPad *recv_rtp_sink;
Packit 1f69a5
  GstPad *recv_rtp_src;
Packit 1f69a5
  GstPad *recv_rtcp_sink;
Packit 1f69a5
  GstPad *rtcp_src;
Packit 1f69a5
};
Packit 1f69a5
Packit 1f69a5
/* find a session with the given id */
Packit 1f69a5
static GstRTPDecSession *
Packit 1f69a5
find_session_by_id (GstRTPDec * rtpdec, gint id)
Packit 1f69a5
{
Packit 1f69a5
  GSList *walk;
Packit 1f69a5
Packit 1f69a5
  for (walk = rtpdec->sessions; walk; walk = g_slist_next (walk)) {
Packit 1f69a5
    GstRTPDecSession *sess = (GstRTPDecSession *) walk->data;
Packit 1f69a5
Packit 1f69a5
    if (sess->id == id)
Packit 1f69a5
      return sess;
Packit 1f69a5
  }
Packit 1f69a5
  return NULL;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
/* create a session with the given id */
Packit 1f69a5
static GstRTPDecSession *
Packit 1f69a5
create_session (GstRTPDec * rtpdec, gint id)
Packit 1f69a5
{
Packit 1f69a5
  GstRTPDecSession *sess;
Packit 1f69a5
Packit 1f69a5
  sess = g_new0 (GstRTPDecSession, 1);
Packit 1f69a5
  sess->id = id;
Packit 1f69a5
  sess->dec = rtpdec;
Packit 1f69a5
  rtpdec->sessions = g_slist_prepend (rtpdec->sessions, sess);
Packit 1f69a5
Packit 1f69a5
  return sess;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
free_session (GstRTPDecSession * session)
Packit 1f69a5
{
Packit 1f69a5
  g_free (session);
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static guint gst_rtp_dec_signals[LAST_SIGNAL] = { 0 };
Packit 1f69a5
Packit 1f69a5
#define gst_rtp_dec_parent_class parent_class
Packit 1f69a5
G_DEFINE_TYPE (GstRTPDec, gst_rtp_dec, GST_TYPE_ELEMENT);
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_rtp_dec_class_init (GstRTPDecClass * g_class)
Packit 1f69a5
{
Packit 1f69a5
  GObjectClass *gobject_class;
Packit 1f69a5
  GstElementClass *gstelement_class;
Packit 1f69a5
  GstRTPDecClass *klass;
Packit 1f69a5
Packit 1f69a5
  klass = (GstRTPDecClass *) g_class;
Packit 1f69a5
  gobject_class = (GObjectClass *) klass;
Packit 1f69a5
  gstelement_class = (GstElementClass *) klass;
Packit 1f69a5
Packit 1f69a5
  GST_DEBUG_CATEGORY_INIT (rtpdec_debug, "rtpdec", 0, "RTP decoder");
Packit 1f69a5
Packit 1f69a5
  gobject_class->finalize = gst_rtp_dec_finalize;
Packit 1f69a5
  gobject_class->set_property = gst_rtp_dec_set_property;
Packit 1f69a5
  gobject_class->get_property = gst_rtp_dec_get_property;
Packit 1f69a5
Packit 1f69a5
  g_object_class_install_property (gobject_class, PROP_LATENCY,
Packit 1f69a5
      g_param_spec_uint ("latency", "Buffer latency in ms",
Packit 1f69a5
          "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS,
Packit 1f69a5
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 1f69a5
Packit 1f69a5
  /**
Packit 1f69a5
   * GstRTPDec::request-pt-map:
Packit 1f69a5
   * @rtpdec: the object which received the signal
Packit 1f69a5
   * @session: the session
Packit 1f69a5
   * @pt: the pt
Packit 1f69a5
   *
Packit 1f69a5
   * Request the payload type as #GstCaps for @pt in @session.
Packit 1f69a5
   */
Packit 1f69a5
  gst_rtp_dec_signals[SIGNAL_REQUEST_PT_MAP] =
Packit 1f69a5
      g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
Packit 1f69a5
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, request_pt_map),
Packit 1f69a5
      NULL, NULL, g_cclosure_marshal_generic, GST_TYPE_CAPS, 2, G_TYPE_UINT,
Packit 1f69a5
      G_TYPE_UINT);
Packit 1f69a5
Packit 1f69a5
  gst_rtp_dec_signals[SIGNAL_CLEAR_PT_MAP] =
Packit 1f69a5
      g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
Packit 1f69a5
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, clear_pt_map),
Packit 1f69a5
      NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
Packit 1f69a5
Packit 1f69a5
  /**
Packit 1f69a5
   * GstRTPDec::on-new-ssrc:
Packit 1f69a5
   * @rtpbin: the object which received the signal
Packit 1f69a5
   * @session: the session
Packit 1f69a5
   * @ssrc: the SSRC 
Packit 1f69a5
   *
Packit 1f69a5
   * Notify of a new SSRC that entered @session.
Packit 1f69a5
   */
Packit 1f69a5
  gst_rtp_dec_signals[SIGNAL_ON_NEW_SSRC] =
Packit 1f69a5
      g_signal_new ("on-new-ssrc", G_TYPE_FROM_CLASS (klass),
Packit 1f69a5
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_new_ssrc),
Packit 1f69a5
      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
Packit 1f69a5
      G_TYPE_UINT);
Packit 1f69a5
  /**
Packit 1f69a5
   * GstRTPDec::on-ssrc_collision:
Packit 1f69a5
   * @rtpbin: the object which received the signal
Packit 1f69a5
   * @session: the session
Packit 1f69a5
   * @ssrc: the SSRC 
Packit 1f69a5
   *
Packit 1f69a5
   * Notify when we have an SSRC collision
Packit 1f69a5
   */
Packit 1f69a5
  gst_rtp_dec_signals[SIGNAL_ON_SSRC_COLLISION] =
Packit 1f69a5
      g_signal_new ("on-ssrc-collision", G_TYPE_FROM_CLASS (klass),
Packit 1f69a5
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_ssrc_collision),
Packit 1f69a5
      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
Packit 1f69a5
      G_TYPE_UINT);
Packit 1f69a5
  /**
Packit 1f69a5
   * GstRTPDec::on-ssrc_validated:
Packit 1f69a5
   * @rtpbin: the object which received the signal
Packit 1f69a5
   * @session: the session
Packit 1f69a5
   * @ssrc: the SSRC 
Packit 1f69a5
   *
Packit 1f69a5
   * Notify of a new SSRC that became validated.
Packit 1f69a5
   */
Packit 1f69a5
  gst_rtp_dec_signals[SIGNAL_ON_SSRC_VALIDATED] =
Packit 1f69a5
      g_signal_new ("on-ssrc-validated", G_TYPE_FROM_CLASS (klass),
Packit 1f69a5
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_ssrc_validated),
Packit 1f69a5
      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
Packit 1f69a5
      G_TYPE_UINT);
Packit 1f69a5
Packit 1f69a5
  /**
Packit 1f69a5
   * GstRTPDec::on-bye-ssrc:
Packit 1f69a5
   * @rtpbin: the object which received the signal
Packit 1f69a5
   * @session: the session
Packit 1f69a5
   * @ssrc: the SSRC 
Packit 1f69a5
   *
Packit 1f69a5
   * Notify of an SSRC that became inactive because of a BYE packet.
Packit 1f69a5
   */
Packit 1f69a5
  gst_rtp_dec_signals[SIGNAL_ON_BYE_SSRC] =
Packit 1f69a5
      g_signal_new ("on-bye-ssrc", G_TYPE_FROM_CLASS (klass),
Packit 1f69a5
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_bye_ssrc),
Packit 1f69a5
      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
Packit 1f69a5
      G_TYPE_UINT);
Packit 1f69a5
  /**
Packit 1f69a5
   * GstRTPDec::on-bye-timeout:
Packit 1f69a5
   * @rtpbin: the object which received the signal
Packit 1f69a5
   * @session: the session
Packit 1f69a5
   * @ssrc: the SSRC 
Packit 1f69a5
   *
Packit 1f69a5
   * Notify of an SSRC that has timed out because of BYE
Packit 1f69a5
   */
Packit 1f69a5
  gst_rtp_dec_signals[SIGNAL_ON_BYE_TIMEOUT] =
Packit 1f69a5
      g_signal_new ("on-bye-timeout", G_TYPE_FROM_CLASS (klass),
Packit 1f69a5
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_bye_timeout),
Packit 1f69a5
      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
Packit 1f69a5
      G_TYPE_UINT);
Packit 1f69a5
  /**
Packit 1f69a5
   * GstRTPDec::on-timeout:
Packit 1f69a5
   * @rtpbin: the object which received the signal
Packit 1f69a5
   * @session: the session
Packit 1f69a5
   * @ssrc: the SSRC 
Packit 1f69a5
   *
Packit 1f69a5
   * Notify of an SSRC that has timed out
Packit 1f69a5
   */
Packit 1f69a5
  gst_rtp_dec_signals[SIGNAL_ON_TIMEOUT] =
Packit 1f69a5
      g_signal_new ("on-timeout", G_TYPE_FROM_CLASS (klass),
Packit 1f69a5
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_timeout),
Packit 1f69a5
      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
Packit 1f69a5
      G_TYPE_UINT);
Packit 1f69a5
Packit 1f69a5
  gstelement_class->provide_clock =
Packit 1f69a5
      GST_DEBUG_FUNCPTR (gst_rtp_dec_provide_clock);
Packit 1f69a5
  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_dec_change_state);
Packit 1f69a5
  gstelement_class->request_new_pad =
Packit 1f69a5
      GST_DEBUG_FUNCPTR (gst_rtp_dec_request_new_pad);
Packit 1f69a5
  gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_dec_release_pad);
Packit 1f69a5
Packit 1f69a5
  /* sink pads */
Packit 1f69a5
  gst_element_class_add_static_pad_template (gstelement_class,
Packit 1f69a5
      &gst_rtp_dec_recv_rtp_sink_template);
Packit 1f69a5
  gst_element_class_add_static_pad_template (gstelement_class,
Packit 1f69a5
      &gst_rtp_dec_recv_rtcp_sink_template);
Packit 1f69a5
  /* src pads */
Packit 1f69a5
  gst_element_class_add_static_pad_template (gstelement_class,
Packit 1f69a5
      &gst_rtp_dec_recv_rtp_src_template);
Packit 1f69a5
  gst_element_class_add_static_pad_template (gstelement_class,
Packit 1f69a5
      &gst_rtp_dec_rtcp_src_template);
Packit 1f69a5
Packit 1f69a5
  gst_element_class_set_static_metadata (gstelement_class, "RTP Decoder",
Packit 1f69a5
      "Codec/Parser/Network",
Packit 1f69a5
      "Accepts raw RTP and RTCP packets and sends them forward",
Packit 1f69a5
      "Wim Taymans <wim.taymans@gmail.com>");
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_rtp_dec_init (GstRTPDec * rtpdec)
Packit 1f69a5
{
Packit 1f69a5
  rtpdec->provided_clock = gst_system_clock_obtain ();
Packit 1f69a5
  rtpdec->latency = DEFAULT_LATENCY_MS;
Packit 1f69a5
Packit 1f69a5
  GST_OBJECT_FLAG_SET (rtpdec, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_rtp_dec_finalize (GObject * object)
Packit 1f69a5
{
Packit 1f69a5
  GstRTPDec *rtpdec;
Packit 1f69a5
Packit 1f69a5
  rtpdec = GST_RTP_DEC (object);
Packit 1f69a5
Packit 1f69a5
  gst_object_unref (rtpdec->provided_clock);
Packit 1f69a5
  g_slist_foreach (rtpdec->sessions, (GFunc) free_session, NULL);
Packit 1f69a5
  g_slist_free (rtpdec->sessions);
Packit 1f69a5
Packit 1f69a5
  G_OBJECT_CLASS (parent_class)->finalize (object);
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static gboolean
Packit 1f69a5
gst_rtp_dec_query_src (GstPad * pad, GstObject * parent, GstQuery * query)
Packit 1f69a5
{
Packit 1f69a5
  gboolean res;
Packit 1f69a5
Packit 1f69a5
  switch (GST_QUERY_TYPE (query)) {
Packit 1f69a5
    case GST_QUERY_LATENCY:
Packit 1f69a5
    {
Packit 1f69a5
      /* we pretend to be live with a 3 second latency */
Packit 1f69a5
      /* FIXME: Do we really have infinite maximum latency? */
Packit 1f69a5
      gst_query_set_latency (query, TRUE, 3 * GST_SECOND, -1);
Packit 1f69a5
      res = TRUE;
Packit 1f69a5
      break;
Packit 1f69a5
    }
Packit 1f69a5
    default:
Packit 1f69a5
      res = gst_pad_query_default (pad, parent, query);
Packit 1f69a5
      break;
Packit 1f69a5
  }
Packit 1f69a5
  return res;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static GstFlowReturn
Packit 1f69a5
gst_rtp_dec_chain_rtp (GstPad * pad, GstObject * parent, GstBuffer * buffer)
Packit 1f69a5
{
Packit 1f69a5
  GstFlowReturn res;
Packit 1f69a5
  GstRTPDec *rtpdec;
Packit 1f69a5
  GstRTPDecSession *session;
Packit 1f69a5
  guint32 ssrc;
Packit 1f69a5
  guint8 pt;
Packit 1f69a5
  GstRTPBuffer rtp = { NULL, };
Packit 1f69a5
Packit 1f69a5
  rtpdec = GST_RTP_DEC (parent);
Packit 1f69a5
Packit 1f69a5
  GST_DEBUG_OBJECT (rtpdec, "got rtp packet");
Packit 1f69a5
Packit 1f69a5
  if (!gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp))
Packit 1f69a5
    goto bad_packet;
Packit 1f69a5
Packit 1f69a5
  ssrc = gst_rtp_buffer_get_ssrc (&rtp;;
Packit 1f69a5
  pt = gst_rtp_buffer_get_payload_type (&rtp;;
Packit 1f69a5
  gst_rtp_buffer_unmap (&rtp;;
Packit 1f69a5
Packit 1f69a5
  GST_DEBUG_OBJECT (rtpdec, "SSRC %08x, PT %d", ssrc, pt);
Packit 1f69a5
Packit 1f69a5
  /* find session */
Packit 1f69a5
  session = gst_pad_get_element_private (pad);
Packit 1f69a5
Packit 1f69a5
  /* see if we have the pad */
Packit 1f69a5
  if (!session->active) {
Packit 1f69a5
    GstPadTemplate *templ;
Packit 1f69a5
    GstElementClass *klass;
Packit 1f69a5
    gchar *name;
Packit 1f69a5
    GstCaps *caps;
Packit 1f69a5
    GValue ret = { 0 };
Packit 1f69a5
    GValue args[3] = { {0}
Packit 1f69a5
    , {0}
Packit 1f69a5
    , {0}
Packit 1f69a5
    };
Packit 1f69a5
Packit 1f69a5
    GST_DEBUG_OBJECT (rtpdec, "creating stream");
Packit 1f69a5
Packit 1f69a5
    session->ssrc = ssrc;
Packit 1f69a5
    session->pt = pt;
Packit 1f69a5
Packit 1f69a5
    /* get pt map */
Packit 1f69a5
    g_value_init (&args[0], GST_TYPE_ELEMENT);
Packit 1f69a5
    g_value_set_object (&args[0], rtpdec);
Packit 1f69a5
    g_value_init (&args[1], G_TYPE_UINT);
Packit 1f69a5
    g_value_set_uint (&args[1], session->id);
Packit 1f69a5
    g_value_init (&args[2], G_TYPE_UINT);
Packit 1f69a5
    g_value_set_uint (&args[2], pt);
Packit 1f69a5
Packit 1f69a5
    g_value_init (&ret, GST_TYPE_CAPS);
Packit 1f69a5
    g_value_set_boxed (&ret, NULL);
Packit 1f69a5
Packit 1f69a5
    g_signal_emitv (args, gst_rtp_dec_signals[SIGNAL_REQUEST_PT_MAP], 0, &ret;;
Packit 1f69a5
Packit 1f69a5
    caps = (GstCaps *) g_value_get_boxed (&ret;;
Packit 1f69a5
Packit 1f69a5
    name = g_strdup_printf ("recv_rtp_src_%u_%u_%u", session->id, ssrc, pt);
Packit 1f69a5
    klass = GST_ELEMENT_GET_CLASS (rtpdec);
Packit 1f69a5
    templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%u_%u_%u");
Packit 1f69a5
    session->recv_rtp_src = gst_pad_new_from_template (templ, name);
Packit 1f69a5
    g_free (name);
Packit 1f69a5
Packit 1f69a5
    gst_pad_set_caps (session->recv_rtp_src, caps);
Packit 1f69a5
Packit 1f69a5
    gst_pad_set_element_private (session->recv_rtp_src, session);
Packit 1f69a5
    gst_pad_set_query_function (session->recv_rtp_src, gst_rtp_dec_query_src);
Packit 1f69a5
    gst_pad_set_active (session->recv_rtp_src, TRUE);
Packit 1f69a5
    gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_src);
Packit 1f69a5
Packit 1f69a5
    session->active = TRUE;
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  res = gst_pad_push (session->recv_rtp_src, buffer);
Packit 1f69a5
Packit 1f69a5
  return res;
Packit 1f69a5
Packit 1f69a5
bad_packet:
Packit 1f69a5
  {
Packit 1f69a5
    GST_ELEMENT_WARNING (rtpdec, STREAM, DECODE, (NULL),
Packit 1f69a5
        ("RTP packet did not validate, dropping"));
Packit 1f69a5
    gst_buffer_unref (buffer);
Packit 1f69a5
    return GST_FLOW_OK;
Packit 1f69a5
  }
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static GstFlowReturn
Packit 1f69a5
gst_rtp_dec_chain_rtcp (GstPad * pad, GstObject * parent, GstBuffer * buffer)
Packit 1f69a5
{
Packit 1f69a5
  GstRTPDec *src;
Packit 1f69a5
Packit 1f69a5
#ifdef HAVE_RTCP
Packit 1f69a5
  gboolean valid;
Packit 1f69a5
  GstRTCPPacket packet;
Packit 1f69a5
  gboolean more;
Packit 1f69a5
#endif
Packit 1f69a5
Packit 1f69a5
  src = GST_RTP_DEC (parent);
Packit 1f69a5
Packit 1f69a5
  GST_DEBUG_OBJECT (src, "got rtcp packet");
Packit 1f69a5
Packit 1f69a5
#ifdef HAVE_RTCP
Packit 1f69a5
  valid = gst_rtcp_buffer_validate (buffer);
Packit 1f69a5
  if (!valid)
Packit 1f69a5
    goto bad_packet;
Packit 1f69a5
Packit 1f69a5
  /* position on first packet */
Packit 1f69a5
  more = gst_rtcp_buffer_get_first_packet (buffer, &packet);
Packit 1f69a5
  while (more) {
Packit 1f69a5
    switch (gst_rtcp_packet_get_type (&packet)) {
Packit 1f69a5
      case GST_RTCP_TYPE_SR:
Packit 1f69a5
      {
Packit 1f69a5
        guint32 ssrc, rtptime, packet_count, octet_count;
Packit 1f69a5
        guint64 ntptime;
Packit 1f69a5
        guint count, i;
Packit 1f69a5
Packit 1f69a5
        gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, &ntptime, &rtptime,
Packit 1f69a5
            &packet_count, &octet_count);
Packit 1f69a5
Packit 1f69a5
        GST_DEBUG_OBJECT (src,
Packit 1f69a5
            "got SR packet: SSRC %08x, NTP %" G_GUINT64_FORMAT
Packit 1f69a5
            ", RTP %u, PC %u, OC %u", ssrc, ntptime, rtptime, packet_count,
Packit 1f69a5
            octet_count);
Packit 1f69a5
Packit 1f69a5
        count = gst_rtcp_packet_get_rb_count (&packet);
Packit 1f69a5
        for (i = 0; i < count; i++) {
Packit 1f69a5
          guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
Packit 1f69a5
          guint8 fractionlost;
Packit 1f69a5
          gint32 packetslost;
Packit 1f69a5
Packit 1f69a5
          gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
Packit 1f69a5
              &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
Packit 1f69a5
Packit 1f69a5
          GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
Packit 1f69a5
              ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
Packit 1f69a5
              packetslost, exthighestseq, jitter, lsr, dlsr);
Packit 1f69a5
        }
Packit 1f69a5
        break;
Packit 1f69a5
      }
Packit 1f69a5
      case GST_RTCP_TYPE_RR:
Packit 1f69a5
      {
Packit 1f69a5
        guint32 ssrc;
Packit 1f69a5
        guint count, i;
Packit 1f69a5
Packit 1f69a5
        ssrc = gst_rtcp_packet_rr_get_ssrc (&packet);
Packit 1f69a5
Packit 1f69a5
        GST_DEBUG_OBJECT (src, "got RR packet: SSRC %08x", ssrc);
Packit 1f69a5
Packit 1f69a5
        count = gst_rtcp_packet_get_rb_count (&packet);
Packit 1f69a5
        for (i = 0; i < count; i++) {
Packit 1f69a5
          guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
Packit 1f69a5
          guint8 fractionlost;
Packit 1f69a5
          gint32 packetslost;
Packit 1f69a5
Packit 1f69a5
          gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
Packit 1f69a5
              &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
Packit 1f69a5
Packit 1f69a5
          GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
Packit 1f69a5
              ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
Packit 1f69a5
              packetslost, exthighestseq, jitter, lsr, dlsr);
Packit 1f69a5
        }
Packit 1f69a5
        break;
Packit 1f69a5
      }
Packit 1f69a5
      case GST_RTCP_TYPE_SDES:
Packit 1f69a5
      {
Packit 1f69a5
        guint chunks, i, j;
Packit 1f69a5
        gboolean more_chunks, more_items;
Packit 1f69a5
Packit 1f69a5
        chunks = gst_rtcp_packet_sdes_get_chunk_count (&packet);
Packit 1f69a5
        GST_DEBUG_OBJECT (src, "got SDES packet with %d chunks", chunks);
Packit 1f69a5
Packit 1f69a5
        more_chunks = gst_rtcp_packet_sdes_first_chunk (&packet);
Packit 1f69a5
        i = 0;
Packit 1f69a5
        while (more_chunks) {
Packit 1f69a5
          guint32 ssrc;
Packit 1f69a5
Packit 1f69a5
          ssrc = gst_rtcp_packet_sdes_get_ssrc (&packet);
Packit 1f69a5
Packit 1f69a5
          GST_DEBUG_OBJECT (src, "chunk %d, SSRC %08x", i, ssrc);
Packit 1f69a5
Packit 1f69a5
          more_items = gst_rtcp_packet_sdes_first_item (&packet);
Packit 1f69a5
          j = 0;
Packit 1f69a5
          while (more_items) {
Packit 1f69a5
            GstRTCPSDESType type;
Packit 1f69a5
            guint8 len;
Packit 1f69a5
            gchar *data;
Packit 1f69a5
Packit 1f69a5
            gst_rtcp_packet_sdes_get_item (&packet, &type, &len, &data);
Packit 1f69a5
Packit 1f69a5
            GST_DEBUG_OBJECT (src, "item %d, type %d, len %d, data %s", j,
Packit 1f69a5
                type, len, data);
Packit 1f69a5
Packit 1f69a5
            more_items = gst_rtcp_packet_sdes_next_item (&packet);
Packit 1f69a5
            j++;
Packit 1f69a5
          }
Packit 1f69a5
          more_chunks = gst_rtcp_packet_sdes_next_chunk (&packet);
Packit 1f69a5
          i++;
Packit 1f69a5
        }
Packit 1f69a5
        break;
Packit 1f69a5
      }
Packit 1f69a5
      case GST_RTCP_TYPE_BYE:
Packit 1f69a5
      {
Packit 1f69a5
        guint count, i;
Packit 1f69a5
        gchar *reason;
Packit 1f69a5
Packit 1f69a5
        reason = gst_rtcp_packet_bye_get_reason (&packet);
Packit 1f69a5
        GST_DEBUG_OBJECT (src, "got BYE packet (reason: %s)",
Packit 1f69a5
            GST_STR_NULL (reason));
Packit 1f69a5
        g_free (reason);
Packit 1f69a5
Packit 1f69a5
        count = gst_rtcp_packet_bye_get_ssrc_count (&packet);
Packit 1f69a5
        for (i = 0; i < count; i++) {
Packit 1f69a5
          guint32 ssrc;
Packit 1f69a5
Packit 1f69a5
Packit 1f69a5
          ssrc = gst_rtcp_packet_bye_get_nth_ssrc (&packet, i);
Packit 1f69a5
Packit 1f69a5
          GST_DEBUG_OBJECT (src, "SSRC: %08x", ssrc);
Packit 1f69a5
        }
Packit 1f69a5
        break;
Packit 1f69a5
      }
Packit 1f69a5
      case GST_RTCP_TYPE_APP:
Packit 1f69a5
        GST_DEBUG_OBJECT (src, "got APP packet");
Packit 1f69a5
        break;
Packit 1f69a5
      default:
Packit 1f69a5
        GST_WARNING_OBJECT (src, "got unknown RTCP packet");
Packit 1f69a5
        break;
Packit 1f69a5
    }
Packit 1f69a5
    more = gst_rtcp_packet_move_to_next (&packet);
Packit 1f69a5
  }
Packit 1f69a5
  gst_buffer_unref (buffer);
Packit 1f69a5
  return GST_FLOW_OK;
Packit 1f69a5
Packit 1f69a5
bad_packet:
Packit 1f69a5
  {
Packit 1f69a5
    GST_WARNING_OBJECT (src, "got invalid RTCP packet");
Packit 1f69a5
    gst_buffer_unref (buffer);
Packit 1f69a5
    return GST_FLOW_OK;
Packit 1f69a5
  }
Packit 1f69a5
#else
Packit 1f69a5
  gst_buffer_unref (buffer);
Packit 1f69a5
  return GST_FLOW_OK;
Packit 1f69a5
#endif
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_rtp_dec_set_property (GObject * object, guint prop_id,
Packit 1f69a5
    const GValue * value, GParamSpec * pspec)
Packit 1f69a5
{
Packit 1f69a5
  GstRTPDec *src;
Packit 1f69a5
Packit 1f69a5
  src = GST_RTP_DEC (object);
Packit 1f69a5
Packit 1f69a5
  switch (prop_id) {
Packit 1f69a5
    case PROP_LATENCY:
Packit 1f69a5
      src->latency = g_value_get_uint (value);
Packit 1f69a5
      break;
Packit 1f69a5
    default:
Packit 1f69a5
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 1f69a5
      break;
Packit 1f69a5
  }
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_rtp_dec_get_property (GObject * object, guint prop_id, GValue * value,
Packit 1f69a5
    GParamSpec * pspec)
Packit 1f69a5
{
Packit 1f69a5
  GstRTPDec *src;
Packit 1f69a5
Packit 1f69a5
  src = GST_RTP_DEC (object);
Packit 1f69a5
Packit 1f69a5
  switch (prop_id) {
Packit 1f69a5
    case PROP_LATENCY:
Packit 1f69a5
      g_value_set_uint (value, src->latency);
Packit 1f69a5
      break;
Packit 1f69a5
    default:
Packit 1f69a5
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 1f69a5
      break;
Packit 1f69a5
  }
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static GstClock *
Packit 1f69a5
gst_rtp_dec_provide_clock (GstElement * element)
Packit 1f69a5
{
Packit 1f69a5
  GstRTPDec *rtpdec;
Packit 1f69a5
Packit 1f69a5
  rtpdec = GST_RTP_DEC (element);
Packit 1f69a5
Packit 1f69a5
  return GST_CLOCK_CAST (gst_object_ref (rtpdec->provided_clock));
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static GstStateChangeReturn
Packit 1f69a5
gst_rtp_dec_change_state (GstElement * element, GstStateChange transition)
Packit 1f69a5
{
Packit 1f69a5
  GstStateChangeReturn ret;
Packit 1f69a5
Packit 1f69a5
  switch (transition) {
Packit 1f69a5
    default:
Packit 1f69a5
      break;
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
Packit 1f69a5
Packit 1f69a5
  switch (transition) {
Packit 1f69a5
    case GST_STATE_CHANGE_READY_TO_PAUSED:
Packit 1f69a5
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
Packit 1f69a5
      /* we're NO_PREROLL when going to PAUSED */
Packit 1f69a5
      ret = GST_STATE_CHANGE_NO_PREROLL;
Packit 1f69a5
      break;
Packit 1f69a5
    default:
Packit 1f69a5
      break;
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  return ret;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
/* Create a pad for receiving RTP for the session in @name
Packit 1f69a5
 */
Packit 1f69a5
static GstPad *
Packit 1f69a5
create_recv_rtp (GstRTPDec * rtpdec, GstPadTemplate * templ, const gchar * name)
Packit 1f69a5
{
Packit 1f69a5
  guint sessid;
Packit 1f69a5
  GstRTPDecSession *session;
Packit 1f69a5
Packit 1f69a5
  /* first get the session number */
Packit 1f69a5
  if (name == NULL || sscanf (name, "recv_rtp_sink_%u", &sessid) != 1)
Packit 1f69a5
    goto no_name;
Packit 1f69a5
Packit 1f69a5
  GST_DEBUG_OBJECT (rtpdec, "finding session %d", sessid);
Packit 1f69a5
Packit 1f69a5
  /* get or create session */
Packit 1f69a5
  session = find_session_by_id (rtpdec, sessid);
Packit 1f69a5
  if (!session) {
Packit 1f69a5
    GST_DEBUG_OBJECT (rtpdec, "creating session %d", sessid);
Packit 1f69a5
    /* create session now */
Packit 1f69a5
    session = create_session (rtpdec, sessid);
Packit 1f69a5
    if (session == NULL)
Packit 1f69a5
      goto create_error;
Packit 1f69a5
  }
Packit 1f69a5
  /* check if pad was requested */
Packit 1f69a5
  if (session->recv_rtp_sink != NULL)
Packit 1f69a5
    goto existed;
Packit 1f69a5
Packit 1f69a5
  GST_DEBUG_OBJECT (rtpdec, "getting RTP sink pad");
Packit 1f69a5
Packit 1f69a5
  session->recv_rtp_sink = gst_pad_new_from_template (templ, name);
Packit 1f69a5
  gst_pad_set_element_private (session->recv_rtp_sink, session);
Packit 1f69a5
  gst_pad_set_chain_function (session->recv_rtp_sink, gst_rtp_dec_chain_rtp);
Packit 1f69a5
  gst_pad_set_active (session->recv_rtp_sink, TRUE);
Packit 1f69a5
  gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_sink);
Packit 1f69a5
Packit 1f69a5
  return session->recv_rtp_sink;
Packit 1f69a5
Packit 1f69a5
  /* ERRORS */
Packit 1f69a5
no_name:
Packit 1f69a5
  {
Packit 1f69a5
    g_warning ("rtpdec: invalid name given");
Packit 1f69a5
    return NULL;
Packit 1f69a5
  }
Packit 1f69a5
create_error:
Packit 1f69a5
  {
Packit 1f69a5
    /* create_session already warned */
Packit 1f69a5
    return NULL;
Packit 1f69a5
  }
Packit 1f69a5
existed:
Packit 1f69a5
  {
Packit 1f69a5
    g_warning ("rtpdec: recv_rtp pad already requested for session %d", sessid);
Packit 1f69a5
    return NULL;
Packit 1f69a5
  }
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
/* Create a pad for receiving RTCP for the session in @name
Packit 1f69a5
 */
Packit 1f69a5
static GstPad *
Packit 1f69a5
create_recv_rtcp (GstRTPDec * rtpdec, GstPadTemplate * templ,
Packit 1f69a5
    const gchar * name)
Packit 1f69a5
{
Packit 1f69a5
  guint sessid;
Packit 1f69a5
  GstRTPDecSession *session;
Packit 1f69a5
Packit 1f69a5
  /* first get the session number */
Packit 1f69a5
  if (name == NULL || sscanf (name, "recv_rtcp_sink_%u", &sessid) != 1)
Packit 1f69a5
    goto no_name;
Packit 1f69a5
Packit 1f69a5
  GST_DEBUG_OBJECT (rtpdec, "finding session %d", sessid);
Packit 1f69a5
Packit 1f69a5
  /* get the session, it must exist or we error */
Packit 1f69a5
  session = find_session_by_id (rtpdec, sessid);
Packit 1f69a5
  if (!session)
Packit 1f69a5
    goto no_session;
Packit 1f69a5
Packit 1f69a5
  /* check if pad was requested */
Packit 1f69a5
  if (session->recv_rtcp_sink != NULL)
Packit 1f69a5
    goto existed;
Packit 1f69a5
Packit 1f69a5
  GST_DEBUG_OBJECT (rtpdec, "getting RTCP sink pad");
Packit 1f69a5
Packit 1f69a5
  session->recv_rtcp_sink = gst_pad_new_from_template (templ, name);
Packit 1f69a5
  gst_pad_set_element_private (session->recv_rtp_sink, session);
Packit 1f69a5
  gst_pad_set_chain_function (session->recv_rtcp_sink, gst_rtp_dec_chain_rtcp);
Packit 1f69a5
  gst_pad_set_active (session->recv_rtcp_sink, TRUE);
Packit 1f69a5
  gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtcp_sink);
Packit 1f69a5
Packit 1f69a5
  return session->recv_rtcp_sink;
Packit 1f69a5
Packit 1f69a5
  /* ERRORS */
Packit 1f69a5
no_name:
Packit 1f69a5
  {
Packit 1f69a5
    g_warning ("rtpdec: invalid name given");
Packit 1f69a5
    return NULL;
Packit 1f69a5
  }
Packit 1f69a5
no_session:
Packit 1f69a5
  {
Packit 1f69a5
    g_warning ("rtpdec: no session with id %d", sessid);
Packit 1f69a5
    return NULL;
Packit 1f69a5
  }
Packit 1f69a5
existed:
Packit 1f69a5
  {
Packit 1f69a5
    g_warning ("rtpdec: recv_rtcp pad already requested for session %d",
Packit 1f69a5
        sessid);
Packit 1f69a5
    return NULL;
Packit 1f69a5
  }
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
/* Create a pad for sending RTCP for the session in @name
Packit 1f69a5
 */
Packit 1f69a5
static GstPad *
Packit 1f69a5
create_rtcp (GstRTPDec * rtpdec, GstPadTemplate * templ, const gchar * name)
Packit 1f69a5
{
Packit 1f69a5
  guint sessid;
Packit 1f69a5
  GstRTPDecSession *session;
Packit 1f69a5
Packit 1f69a5
  /* first get the session number */
Packit 1f69a5
  if (name == NULL || sscanf (name, "rtcp_src_%u", &sessid) != 1)
Packit 1f69a5
    goto no_name;
Packit 1f69a5
Packit 1f69a5
  /* get or create session */
Packit 1f69a5
  session = find_session_by_id (rtpdec, sessid);
Packit 1f69a5
  if (!session)
Packit 1f69a5
    goto no_session;
Packit 1f69a5
Packit 1f69a5
  /* check if pad was requested */
Packit 1f69a5
  if (session->rtcp_src != NULL)
Packit 1f69a5
    goto existed;
Packit 1f69a5
Packit 1f69a5
  session->rtcp_src = gst_pad_new_from_template (templ, name);
Packit 1f69a5
  gst_pad_set_active (session->rtcp_src, TRUE);
Packit 1f69a5
  gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->rtcp_src);
Packit 1f69a5
Packit 1f69a5
  return session->rtcp_src;
Packit 1f69a5
Packit 1f69a5
  /* ERRORS */
Packit 1f69a5
no_name:
Packit 1f69a5
  {
Packit 1f69a5
    g_warning ("rtpdec: invalid name given");
Packit 1f69a5
    return NULL;
Packit 1f69a5
  }
Packit 1f69a5
no_session:
Packit 1f69a5
  {
Packit 1f69a5
    g_warning ("rtpdec: session with id %d does not exist", sessid);
Packit 1f69a5
    return NULL;
Packit 1f69a5
  }
Packit 1f69a5
existed:
Packit 1f69a5
  {
Packit 1f69a5
    g_warning ("rtpdec: rtcp_src pad already requested for session %d", sessid);
Packit 1f69a5
    return NULL;
Packit 1f69a5
  }
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
/* 
Packit 1f69a5
 */
Packit 1f69a5
static GstPad *
Packit 1f69a5
gst_rtp_dec_request_new_pad (GstElement * element,
Packit 1f69a5
    GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
Packit 1f69a5
{
Packit 1f69a5
  GstRTPDec *rtpdec;
Packit 1f69a5
  GstElementClass *klass;
Packit 1f69a5
  GstPad *result;
Packit 1f69a5
Packit 1f69a5
  g_return_val_if_fail (templ != NULL, NULL);
Packit 1f69a5
  g_return_val_if_fail (GST_IS_RTP_DEC (element), NULL);
Packit 1f69a5
Packit 1f69a5
  rtpdec = GST_RTP_DEC (element);
Packit 1f69a5
  klass = GST_ELEMENT_GET_CLASS (element);
Packit 1f69a5
Packit 1f69a5
  /* figure out the template */
Packit 1f69a5
  if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%u")) {
Packit 1f69a5
    result = create_recv_rtp (rtpdec, templ, name);
Packit 1f69a5
  } else if (templ == gst_element_class_get_pad_template (klass,
Packit 1f69a5
          "recv_rtcp_sink_%u")) {
Packit 1f69a5
    result = create_recv_rtcp (rtpdec, templ, name);
Packit 1f69a5
  } else if (templ == gst_element_class_get_pad_template (klass, "rtcp_src_%u")) {
Packit 1f69a5
    result = create_rtcp (rtpdec, templ, name);
Packit 1f69a5
  } else
Packit 1f69a5
    goto wrong_template;
Packit 1f69a5
Packit 1f69a5
  return result;
Packit 1f69a5
Packit 1f69a5
  /* ERRORS */
Packit 1f69a5
wrong_template:
Packit 1f69a5
  {
Packit 1f69a5
    g_warning ("rtpdec: this is not our template");
Packit 1f69a5
    return NULL;
Packit 1f69a5
  }
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_rtp_dec_release_pad (GstElement * element, GstPad * pad)
Packit 1f69a5
{
Packit 1f69a5
}