Example #1
0
/* Return a stream structure for a given buffer
 */
static GstSrtpDecSsrcStream *
validate_buffer (GstSrtpDec * filter, GstBuffer * buf, guint32 * ssrc,
    gboolean * is_rtcp)
{
  GstSrtpDecSsrcStream *stream = NULL;
  GstRTPBuffer rtpbuf = GST_RTP_BUFFER_INIT;

  if (gst_rtp_buffer_map (buf, GST_MAP_READ, &rtpbuf)) {
    if (gst_rtp_buffer_get_payload_type (&rtpbuf) < 64
        || gst_rtp_buffer_get_payload_type (&rtpbuf) > 80) {
      *ssrc = gst_rtp_buffer_get_ssrc (&rtpbuf);

      gst_rtp_buffer_unmap (&rtpbuf);
      *is_rtcp = FALSE;
      goto have_ssrc;
    }
    gst_rtp_buffer_unmap (&rtpbuf);
  }

  if (rtcp_buffer_get_ssrc (buf, ssrc)) {
    *is_rtcp = TRUE;
  } else {
    GST_WARNING_OBJECT (filter, "No SSRC found in buffer");
    return NULL;
  }

have_ssrc:

  stream = find_stream_by_ssrc (filter, *ssrc);

  if (stream)
    return stream;

  return request_key_with_signal (filter, *ssrc, SIGNAL_REQUEST_KEY);
}
Example #2
0
static GstPadProbeReturn
rtpsession_sinkpad_probe2 (GstPad * pad, GstPadProbeInfo * info,
    gpointer user_data)
{
  GstPadProbeReturn ret = GST_PAD_PROBE_OK;

  if (info->type == (GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_PUSH)) {
    GstBuffer *buffer = GST_BUFFER (info->data);
    GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
    guint payload_type = 0;

    static gint i = 0;

    /* retrieve current ssrc for retransmission stream only */
    gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp);
    payload_type = gst_rtp_buffer_get_payload_type (&rtp);
    if (payload_type == 99) {
      if (i < 3)
        rtx_ssrc_before = gst_rtp_buffer_get_ssrc (&rtp);
      else
        rtx_ssrc_after = gst_rtp_buffer_get_ssrc (&rtp);
    } else {
      /* ask to retransmit every packet */
      GstEvent *event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
          gst_structure_new ("GstRTPRetransmissionRequest",
              "seqnum", G_TYPE_UINT, gst_rtp_buffer_get_seq (&rtp),
              "ssrc", G_TYPE_UINT, gst_rtp_buffer_get_ssrc (&rtp),
              NULL));
      gst_pad_push_event (pad, event);

      if (i < 3)
        ssrc_before = gst_rtp_buffer_get_ssrc (&rtp);
      else
        ssrc_after = gst_rtp_buffer_get_ssrc (&rtp);
    }
    gst_rtp_buffer_unmap (&rtp);

    /* feint a collision on recv_rtcp_sink pad of gstrtpsession
     * (note that after being marked as collied the rtpsession ignores
     * all non bye packets)
     */
    if (i == 2) {
      GstBuffer *rtcp_buffer = create_rtcp_app (rtx_ssrc_before, 0);

      /* push collied packet on recv_rtcp_sink */
      gst_pad_push (srcpad, rtcp_buffer);
    }

    ++i;
  }

  return ret;
}
static void
compare_rtp_packets (GstBuffer * a, GstBuffer * b)
{
  GstRTPBuffer rtp_a = GST_RTP_BUFFER_INIT;
  GstRTPBuffer rtp_b = GST_RTP_BUFFER_INIT;

  gst_rtp_buffer_map (a, GST_MAP_READ, &rtp_a);
  gst_rtp_buffer_map (b, GST_MAP_READ, &rtp_b);

  fail_unless_equals_int (gst_rtp_buffer_get_header_len (&rtp_a),
      gst_rtp_buffer_get_header_len (&rtp_b));
  fail_unless_equals_int (gst_rtp_buffer_get_version (&rtp_a),
      gst_rtp_buffer_get_version (&rtp_b));
  fail_unless_equals_int (gst_rtp_buffer_get_ssrc (&rtp_a),
      gst_rtp_buffer_get_ssrc (&rtp_b));
  fail_unless_equals_int (gst_rtp_buffer_get_seq (&rtp_a),
      gst_rtp_buffer_get_seq (&rtp_b));
  fail_unless_equals_int (gst_rtp_buffer_get_csrc_count (&rtp_a),
      gst_rtp_buffer_get_csrc_count (&rtp_b));
  fail_unless_equals_int (gst_rtp_buffer_get_marker (&rtp_a),
      gst_rtp_buffer_get_marker (&rtp_b));
  fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp_a),
      gst_rtp_buffer_get_payload_type (&rtp_b));
  fail_unless_equals_int (gst_rtp_buffer_get_timestamp (&rtp_a),
      gst_rtp_buffer_get_timestamp (&rtp_b));
  fail_unless_equals_int (gst_rtp_buffer_get_extension (&rtp_a),
      gst_rtp_buffer_get_extension (&rtp_b));

  fail_unless_equals_int (gst_rtp_buffer_get_payload_len (&rtp_a),
      gst_rtp_buffer_get_payload_len (&rtp_b));
  fail_unless_equals_int (memcmp (gst_rtp_buffer_get_payload (&rtp_a),
          gst_rtp_buffer_get_payload (&rtp_b),
          gst_rtp_buffer_get_payload_len (&rtp_a)), 0);

  gst_rtp_buffer_unmap (&rtp_a);
  gst_rtp_buffer_unmap (&rtp_b);
}
static void
gst_rtp_ulpfec_dec_start (GstRtpUlpFecDec * self, GstBufferList * buflist,
    guint8 fec_pt, guint16 lost_seq)
{
  guint fec_packets = 0;
  gsize i;

  g_assert (NULL == self->info_media);
  g_assert (0 == self->info_fec->len);
  g_assert (0 == self->info_arr->len);

  g_array_set_size (self->info_arr, gst_buffer_list_length (buflist));

  for (i = 0;
      i < gst_buffer_list_length (buflist) && !self->lost_packet_from_storage;
      ++i) {
    GstBuffer *buffer = gst_buffer_list_get (buflist, i);
    RtpUlpFecMapInfo *info = RTP_FEC_MAP_INFO_NTH (self, i);

    if (!rtp_ulpfec_map_info_map (gst_buffer_ref (buffer), info))
      g_assert_not_reached ();

    if (fec_pt == gst_rtp_buffer_get_payload_type (&info->rtp)) {
      GST_DEBUG_RTP_PACKET (self, "rtp header (fec)", &info->rtp);

      ++fec_packets;
      if (rtp_ulpfec_buffer_is_valid (&info->rtp)) {
        GST_DEBUG_FEC_PACKET (self, &info->rtp);
        g_ptr_array_add (self->info_fec, GUINT_TO_POINTER (i));
      }
    } else {
      GST_LOG_RTP_PACKET (self, "rtp header (incoming)", &info->rtp);

      if (lost_seq == gst_rtp_buffer_get_seq (&info->rtp)) {
        GST_DEBUG_OBJECT (self, "Received lost packet from from the storage");
        g_list_free (self->info_media);
        self->info_media = NULL;
        self->lost_packet_from_storage = TRUE;
      }
      self->info_media =
          g_list_insert_sorted_with_data (self->info_media,
          GUINT_TO_POINTER (i), _compare_fec_map_info, self);
    }
  }
  if (!self->lost_packet_from_storage) {
    self->fec_packets_received += fec_packets;
    self->fec_packets_rejected += fec_packets - self->info_fec->len;
  }
}
static gboolean
gst_rtp_ulpfec_dec_is_recovered_pt_valid (GstRtpUlpFecDec * self, gint media_pt,
    guint8 recovered_pt)
{
  GList *it;
  if (media_pt == recovered_pt)
    return TRUE;

  for (it = self->info_media; it; it = it->next) {
    RtpUlpFecMapInfo *info = RTP_FEC_MAP_INFO_NTH (self, it->data);
    if (gst_rtp_buffer_get_payload_type (&info->rtp) == recovered_pt)
      return TRUE;
  }
  return FALSE;
}
static GstFlowReturn gst_scream_queue_sink_chain(GstPad *pad, GstObject *parent, GstBuffer *buffer)
{
    GstScreamQueue *self = GST_SCREAM_QUEUE(parent);
    GstRTPBuffer rtp_buffer = GST_RTP_BUFFER_INIT;
    GstFlowReturn flow_ret = GST_FLOW_OK;
    GstScreamDataQueueRtpItem *rtp_item;

    if (GST_PAD_IS_FLUSHING(pad)) {
        flow_ret = GST_FLOW_FLUSHING;
        goto end;
    }

    if (!gst_rtp_buffer_map(buffer, GST_MAP_READ, &rtp_buffer)) {
        flow_ret = GST_FLOW_ERROR;
        goto end;
    }

    rtp_item = g_slice_new(GstScreamDataQueueRtpItem);
    ((GstDataQueueItem *)rtp_item)->object = GST_MINI_OBJECT(buffer);
    ((GstDataQueueItem *)rtp_item)->size = gst_buffer_get_size(buffer);
    ((GstDataQueueItem *)rtp_item)->visible = TRUE;
    ((GstDataQueueItem *)rtp_item)->duration = GST_BUFFER_DURATION(buffer);
    ((GstDataQueueItem *)rtp_item)->destroy = (GDestroyNotify) gst_scream_data_queue_rtp_item_free;

    ((GstScreamDataQueueItem *)rtp_item)->type = GST_SCREAM_DATA_QUEUE_ITEM_TYPE_RTP;
    ((GstScreamDataQueueItem *)rtp_item)->rtp_ssrc = gst_rtp_buffer_get_ssrc(&rtp_buffer);
    rtp_item->rtp_pt = gst_rtp_buffer_get_payload_type(&rtp_buffer);
    rtp_item->gst_ts = GST_BUFFER_PTS(buffer);
    rtp_item->rtp_seq = gst_rtp_buffer_get_seq(&rtp_buffer);
    rtp_item->rtp_ts = gst_rtp_buffer_get_timestamp(&rtp_buffer);
    rtp_item->rtp_marker = gst_rtp_buffer_get_marker(&rtp_buffer);
    rtp_item->rtp_payload_size = gst_rtp_buffer_get_payload_len(&rtp_buffer);
    rtp_item->enqueued_time = get_gst_time_us(self);
    gst_rtp_buffer_unmap(&rtp_buffer);

    if (self->pass_through) {
        rtp_item->adapted = FALSE;
        GST_LOG_OBJECT(self, "passing through: pt = %u, seq: %u, pass: %u", rtp_item->rtp_pt, rtp_item->rtp_seq, self->pass_through);
        gst_data_queue_push(self->approved_packets, (GstDataQueueItem *)rtp_item);
        goto end;
    }

    GST_LOG_OBJECT(self, "queuing: pt = %u, seq: %u, pass: %u", rtp_item->rtp_pt, rtp_item->rtp_seq, self->pass_through);
    g_async_queue_push(self->incoming_packets, (gpointer)rtp_item);

end:
    return flow_ret;
}
static GstBuffer *
gst_rtp_ulpfec_dec_recover_from_storage (GstRtpUlpFecDec * self,
    guint8 * dst_pt, guint16 * dst_seq)
{
  RtpUlpFecMapInfo *info;

  if (self->lost_packet_returned)
    return NULL;

  g_assert (g_list_length (self->info_media) == 1);

  info = RTP_FEC_MAP_INFO_NTH (self, self->info_media->data);
  *dst_seq = gst_rtp_buffer_get_seq (&info->rtp);
  *dst_pt = gst_rtp_buffer_get_payload_type (&info->rtp);
  self->lost_packet_returned = TRUE;
  GST_DEBUG_RTP_PACKET (self, "rtp header (recovered)", &info->rtp);
  return gst_buffer_ref (info->rtp.buffer);
}
Example #8
0
static void
packet_recovered_cb (GObject * internal_storage, GstBuffer * buffer,
    GList * infos)
{
  gboolean found = FALSE;
  GstRTPBuffer rtp = { NULL };

  fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));

  for (GList * it = infos; it; it = it->next) {
    RecoveredPacketInfo *info = it->data;
    if (gst_rtp_buffer_get_seq (&rtp) == info->seq) {
      fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp), info->pt);
      fail_unless_equals_int (gst_rtp_buffer_get_ssrc (&rtp), info->ssrc);
      found = TRUE;
      break;
    }
  }

  gst_rtp_buffer_unmap (&rtp);
  fail_unless (found);
}
Example #9
0
static void
send_dmtf_havedata_handler (GstPad *pad, GstBuffer *buf, gpointer user_data)
{
  gchar *data;

  ts_fail_unless (gst_rtp_buffer_validate (buf), "Buffer is not valid rtp");

  if (gst_rtp_buffer_get_payload_type (buf) != dtmf_id)
    return;

  data = gst_rtp_buffer_get_payload (buf);

  if (data[0] < digit)
  {
    /* Still on previou digit */
    return;
  }

  ts_fail_if (data[0] != digit, "Not sending the right digit"
      " (sending %d, should be %d", data[0], digit);

  received = TRUE;
}
Example #10
0
static GstPadProbeReturn
rtprtxsend_srcpad_probe (GstPad * pad, GstPadProbeInfo * info,
    gpointer user_data)
{
  GstPadProbeReturn ret = GST_PAD_PROBE_OK;

  if (info->type == (GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_PUSH)) {
    GstBuffer *buffer = GST_BUFFER (info->data);
    RTXSendData *rtxdata = (RTXSendData *) user_data;
    GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
    guint payload_type = 0;

    gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp);
    payload_type = gst_rtp_buffer_get_payload_type (&rtp);

    /* main stream packets */
    if (payload_type == 96) {
      /* count packets of the main stream */
      ++rtxdata->nb_packets;
      /* drop some packets */
      if (rtxdata->count < rtxdata->drop_every_n_packets) {
        ++rtxdata->count;
      } else {
        /* drop a packet every 'rtxdata->count' packets */
        rtxdata->count = 1;
        ret = GST_PAD_PROBE_DROP;
      }
    } else {
      /* retransmission packets */
    }

    gst_rtp_buffer_unmap (&rtp);
  }

  return ret;
}
Example #11
0
gboolean
kms_rtp_synchronizer_process_rtp_buffer_mapped (KmsRtpSynchronizer * self,
    GstRTPBuffer * rtp_buffer, GError ** error)
{
  GstBuffer *buffer = rtp_buffer->buffer;
  guint64 pts_orig, ext_ts, last_sr_ext_ts, last_sr_ntp_ns_time;
  guint64 diff_ntp_ns_time;
  guint8 pt;
  guint32 ssrc, ts;
  gint32 clock_rate;
  gboolean ret = TRUE;

  ssrc = gst_rtp_buffer_get_ssrc (rtp_buffer);

  KMS_RTP_SYNCHRONIZER_LOCK (self);

  if (self->priv->ssrc == 0) {
    self->priv->ssrc = ssrc;
  } else if (ssrc != self->priv->ssrc) {
    gchar *msg = g_strdup_printf ("Invalid SSRC (%u), not matching with %u",
        ssrc, self->priv->ssrc);

    GST_ERROR_OBJECT (self, "%s", msg);
    g_set_error_literal (error, KMS_RTP_SYNC_ERROR, KMS_RTP_SYNC_INVALID_DATA,
        msg);
    g_free (msg);

    KMS_RTP_SYNCHRONIZER_UNLOCK (self);

    return FALSE;
  }

  pt = gst_rtp_buffer_get_payload_type (rtp_buffer);
  if (pt != self->priv->pt || self->priv->clock_rate <= 0) {
    gchar *msg =
        g_strdup_printf ("Invalid clock-rate %d for PT %u, not changing PTS",
        self->priv->clock_rate, pt);

    GST_ERROR_OBJECT (self, "%s", msg);
    g_set_error_literal (error, KMS_RTP_SYNC_ERROR, KMS_RTP_SYNC_INVALID_DATA,
        msg);
    g_free (msg);

    KMS_RTP_SYNCHRONIZER_UNLOCK (self);

    return FALSE;
  }

  pts_orig = GST_BUFFER_PTS (buffer);
  ts = gst_rtp_buffer_get_timestamp (rtp_buffer);
  gst_rtp_buffer_ext_timestamp (&self->priv->ext_ts, ts);

  if (self->priv->feeded_sorted) {
    if (self->priv->fs_last_ext_ts != -1
        && self->priv->ext_ts < self->priv->fs_last_ext_ts) {
      guint16 seq = gst_rtp_buffer_get_seq (rtp_buffer);
      gchar *msg =
          g_strdup_printf
          ("Received an unsorted RTP buffer when expecting sorted (ssrc: %"
          G_GUINT32_FORMAT ", seq: %" G_GUINT16_FORMAT ", ts: %"
          G_GUINT32_FORMAT ", ext_ts: %" G_GUINT64_FORMAT
          "). Moving to unsorted mode",
          ssrc, seq, ts, self->priv->ext_ts);

      GST_ERROR_OBJECT (self, "%s", msg);
      g_set_error_literal (error, KMS_RTP_SYNC_ERROR, KMS_RTP_SYNC_INVALID_DATA,
          msg);
      g_free (msg);

      self->priv->feeded_sorted = FALSE;
      ret = FALSE;
    } else if (self->priv->ext_ts == self->priv->fs_last_ext_ts) {
      GST_BUFFER_PTS (buffer) = self->priv->fs_last_pts;
      goto end;
    }
  }

  if (!self->priv->base_initiated) {
    GST_DEBUG_OBJECT (self,
        "Do not sync data for SSRC %u and PT %u, interpolating PTS", ssrc, pt);

    if (!self->priv->base_interpolate_initiated) {
      self->priv->base_interpolate_ext_ts = self->priv->ext_ts;
      self->priv->base_interpolate_time = GST_BUFFER_PTS (buffer);
      self->priv->base_interpolate_initiated = TRUE;
    } else {
      buffer = gst_buffer_make_writable (buffer);
      GST_BUFFER_PTS (buffer) = self->priv->base_interpolate_time;
      kms_rtp_synchronizer_rtp_diff (self, rtp_buffer, self->priv->clock_rate,
          self->priv->base_interpolate_ext_ts);
    }
  } else {
    gboolean wrapped_down, wrapped_up;

    wrapped_down = wrapped_up = FALSE;

    buffer = gst_buffer_make_writable (buffer);
    GST_BUFFER_PTS (buffer) = self->priv->base_sync_time;

    if (self->priv->last_sr_ntp_ns_time > self->priv->base_ntp_ns_time) {
      diff_ntp_ns_time =
          self->priv->last_sr_ntp_ns_time - self->priv->base_ntp_ns_time;
      wrapped_up = diff_ntp_ns_time > (G_MAXUINT64 - GST_BUFFER_PTS (buffer));
      GST_BUFFER_PTS (buffer) += diff_ntp_ns_time;
    } else if (self->priv->last_sr_ntp_ns_time < self->priv->base_ntp_ns_time) {
      diff_ntp_ns_time =
          self->priv->base_ntp_ns_time - self->priv->last_sr_ntp_ns_time;
      wrapped_down = GST_BUFFER_PTS (buffer) < diff_ntp_ns_time;
      GST_BUFFER_PTS (buffer) -= diff_ntp_ns_time;
    }
    /* if equals do nothing */

    kms_rtp_synchronizer_rtp_diff_full (self, rtp_buffer,
        self->priv->clock_rate, self->priv->last_sr_ext_ts, wrapped_down,
        wrapped_up);
  }

  if (self->priv->feeded_sorted) {
    if (GST_BUFFER_PTS (buffer) < self->priv->fs_last_pts) {
      guint16 seq = gst_rtp_buffer_get_seq (rtp_buffer);

      GST_WARNING_OBJECT (self,
          "Non monotonic PTS assignment in sorted mode (ssrc: %"
          G_GUINT32_FORMAT ", seq: %" G_GUINT16_FORMAT ", ts: %"
          G_GUINT32_FORMAT ", ext_ts: %" G_GUINT64_FORMAT
          "). Forcing monotonic", ssrc, seq, ts, self->priv->ext_ts);

      GST_BUFFER_PTS (buffer) = self->priv->fs_last_pts;
    }

    self->priv->fs_last_ext_ts = self->priv->ext_ts;
    self->priv->fs_last_pts = GST_BUFFER_PTS (buffer);
  }

end:
  clock_rate = self->priv->clock_rate;
  ext_ts = self->priv->ext_ts;
  last_sr_ext_ts = self->priv->last_sr_ext_ts;
  last_sr_ntp_ns_time = self->priv->last_sr_ntp_ns_time;

  KMS_RTP_SYNCHRONIZER_UNLOCK (self);

  kms_rtp_sync_context_write_stats (self->priv->context, ssrc, clock_rate,
      pts_orig, GST_BUFFER_PTS (buffer), GST_BUFFER_DTS (buffer), ext_ts,
      last_sr_ntp_ns_time, last_sr_ext_ts);

  return ret;
}
Example #12
0
static GstFlowReturn
gst_rtp_jitter_buffer_chain (GstPad * pad, GstBuffer * buffer)
{
  GstRtpJitterBuffer *jitterbuffer;
  GstRtpJitterBufferPrivate *priv;
  guint16 seqnum;
  GstFlowReturn ret = GST_FLOW_OK;
  GstClockTime timestamp;
  guint64 latency_ts;
  gboolean tail;

  jitterbuffer = GST_RTP_JITTER_BUFFER (gst_pad_get_parent (pad));

  if (!gst_rtp_buffer_validate (buffer))
    goto invalid_buffer;

  priv = jitterbuffer->priv;

  if (priv->last_pt != gst_rtp_buffer_get_payload_type (buffer)) {
    GstCaps *caps;

    priv->last_pt = gst_rtp_buffer_get_payload_type (buffer);
    /* reset clock-rate so that we get a new one */
    priv->clock_rate = -1;
    /* Try to get the clock-rate from the caps first if we can. If there are no
     * caps we must fire the signal to get the clock-rate. */
    if ((caps = GST_BUFFER_CAPS (buffer))) {
      gst_jitter_buffer_sink_parse_caps (jitterbuffer, caps);
    }
  }

  if (priv->clock_rate == -1) {
    guint8 pt;

    /* no clock rate given on the caps, try to get one with the signal */
    pt = gst_rtp_buffer_get_payload_type (buffer);

    gst_rtp_jitter_buffer_get_clock_rate (jitterbuffer, pt);
    if (priv->clock_rate == -1)
      goto not_negotiated;
  }

  /* take the timestamp of the buffer. This is the time when the packet was
   * received and is used to calculate jitter and clock skew. We will adjust
   * this timestamp with the smoothed value after processing it in the
   * jitterbuffer. */
  timestamp = GST_BUFFER_TIMESTAMP (buffer);
  /* bring to running time */
  timestamp = gst_segment_to_running_time (&priv->segment, GST_FORMAT_TIME,
      timestamp);

  seqnum = gst_rtp_buffer_get_seq (buffer);
  GST_DEBUG_OBJECT (jitterbuffer,
      "Received packet #%d at time %" GST_TIME_FORMAT, seqnum,
      GST_TIME_ARGS (timestamp));

  JBUF_LOCK_CHECK (priv, out_flushing);
  /* don't accept more data on EOS */
  if (priv->eos)
    goto have_eos;

  /* let's check if this buffer is too late, we can only accept packets with
   * bigger seqnum than the one we last pushed. */
  if (priv->last_popped_seqnum != -1) {
    gint gap;

    gap = gst_rtp_buffer_compare_seqnum (priv->last_popped_seqnum, seqnum);

    if (gap <= 0) {
      /* priv->last_popped_seqnum >= seqnum, this packet is too late or the
       * sender might have been restarted with different seqnum. */
      if (gap < -100) {
        GST_DEBUG_OBJECT (jitterbuffer, "reset: buffer too old %d", gap);
        priv->last_popped_seqnum = -1;
        priv->next_seqnum = -1;
      } else {
        goto too_late;
      }
    } else {
      /* priv->last_popped_seqnum < seqnum, this is a new packet */
      if (gap > 3000) {
        GST_DEBUG_OBJECT (jitterbuffer, "reset: too many dropped packets %d",
            gap);
        priv->last_popped_seqnum = -1;
        priv->next_seqnum = -1;
      }
    }
  }

  /* let's drop oldest packet if the queue is already full and drop-on-latency
   * is set. We can only do this when there actually is a latency. When no
   * latency is set, we just pump it in the queue and let the other end push it
   * out as fast as possible. */
  if (priv->latency_ms && priv->drop_on_latency) {

    latency_ts =
        gst_util_uint64_scale_int (priv->latency_ms, priv->clock_rate, 1000);

    if (rtp_jitter_buffer_get_ts_diff (priv->jbuf) >= latency_ts) {
      GstBuffer *old_buf;

      GST_DEBUG_OBJECT (jitterbuffer, "Queue full, dropping old packet #%d",
          seqnum);

      old_buf = rtp_jitter_buffer_pop (priv->jbuf);
      gst_buffer_unref (old_buf);
    }
  }

  /* now insert the packet into the queue in sorted order. This function returns
   * FALSE if a packet with the same seqnum was already in the queue, meaning we
   * have a duplicate. */
  if (!rtp_jitter_buffer_insert (priv->jbuf, buffer, timestamp,
          priv->clock_rate, &tail))
    goto duplicate;

  /* signal addition of new buffer when the _loop is waiting. */
  if (priv->waiting)
    JBUF_SIGNAL (priv);

  /* let's unschedule and unblock any waiting buffers. We only want to do this
   * when the tail buffer changed */
  if (priv->clock_id && tail) {
    GST_DEBUG_OBJECT (jitterbuffer,
        "Unscheduling waiting buffer, new tail buffer");
    gst_clock_id_unschedule (priv->clock_id);
  }

  GST_DEBUG_OBJECT (jitterbuffer, "Pushed packet #%d, now %d packets",
      seqnum, rtp_jitter_buffer_num_packets (priv->jbuf));

finished:
  JBUF_UNLOCK (priv);

  gst_object_unref (jitterbuffer);

  return ret;

  /* ERRORS */
invalid_buffer:
  {
    /* this is not fatal but should be filtered earlier */
    GST_ELEMENT_WARNING (jitterbuffer, STREAM, DECODE, (NULL),
        ("Received invalid RTP payload, dropping"));
    gst_buffer_unref (buffer);
    gst_object_unref (jitterbuffer);
    return GST_FLOW_OK;
  }
not_negotiated:
  {
    GST_WARNING_OBJECT (jitterbuffer, "No clock-rate in caps!");
    gst_buffer_unref (buffer);
    gst_object_unref (jitterbuffer);
    return GST_FLOW_OK;
  }
out_flushing:
  {
    ret = priv->srcresult;
    GST_DEBUG_OBJECT (jitterbuffer, "flushing %s", gst_flow_get_name (ret));
    gst_buffer_unref (buffer);
    goto finished;
  }
have_eos:
  {
    ret = GST_FLOW_UNEXPECTED;
    GST_WARNING_OBJECT (jitterbuffer, "we are EOS, refusing buffer");
    gst_buffer_unref (buffer);
    goto finished;
  }
too_late:
  {
    GST_WARNING_OBJECT (jitterbuffer, "Packet #%d too late as #%d was already"
        " popped, dropping", seqnum, priv->last_popped_seqnum);
    priv->num_late++;
    gst_buffer_unref (buffer);
    goto finished;
  }
duplicate:
  {
    GST_WARNING_OBJECT (jitterbuffer, "Duplicate packet #%d detected, dropping",
        seqnum);
    priv->num_duplicates++;
    gst_buffer_unref (buffer);
    goto finished;
  }
}
Example #13
0
static GstFlowReturn
gst_rtp_pt_demux_chain (GstPad * pad, GstBuffer * buf)
{
  GstFlowReturn ret = GST_FLOW_OK;
  GstRtpPtDemux *rtpdemux;
  GstElement *element = GST_ELEMENT (GST_OBJECT_PARENT (pad));
  guint8 pt;
  GstPad *srcpad;
  GstRtpPtDemuxPad *rtpdemuxpad;
  GstCaps *caps;

  rtpdemux = GST_RTP_PT_DEMUX (GST_OBJECT_PARENT (pad));

  if (!gst_rtp_buffer_validate (buf))
    goto invalid_buffer;

  pt = gst_rtp_buffer_get_payload_type (buf);

  GST_DEBUG_OBJECT (rtpdemux, "received buffer for pt %d", pt);

  rtpdemuxpad = find_pad_for_pt (rtpdemux, pt);
  if (rtpdemuxpad == NULL) {
    /* new PT, create a src pad */
    GstElementClass *klass;
    GstPadTemplate *templ;
    gchar *padname;

    klass = GST_ELEMENT_GET_CLASS (rtpdemux);
    templ = gst_element_class_get_pad_template (klass, "src_%d");
    padname = g_strdup_printf ("src_%d", pt);
    srcpad = gst_pad_new_from_template (templ, padname);
    gst_pad_use_fixed_caps (srcpad);
    g_free (padname);

    caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt);
    if (!caps)
      goto no_caps;

    caps = gst_caps_make_writable (caps);
    gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
    gst_pad_set_caps (srcpad, caps);
    gst_caps_unref (caps);

    GST_DEBUG ("Adding pt=%d to the list.", pt);
    rtpdemuxpad = g_new0 (GstRtpPtDemuxPad, 1);
    rtpdemuxpad->pt = pt;
    rtpdemuxpad->newcaps = FALSE;
    rtpdemuxpad->pad = srcpad;
    GST_OBJECT_LOCK (rtpdemux);
    rtpdemux->srcpads = g_slist_append (rtpdemux->srcpads, rtpdemuxpad);
    GST_OBJECT_UNLOCK (rtpdemux);

    gst_pad_set_active (srcpad, TRUE);
    gst_element_add_pad (element, srcpad);

    GST_DEBUG ("emitting new-payload-type for pt %d", pt);
    g_signal_emit (G_OBJECT (rtpdemux),
        gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE], 0, pt, srcpad);
  }

  srcpad = rtpdemuxpad->pad;

  if (pt != rtpdemux->last_pt) {
    gint emit_pt = pt;

    /* our own signal with an extra flag that this is the only pad */
    rtpdemux->last_pt = pt;
    GST_DEBUG ("emitting payload-type-changed for pt %d", emit_pt);
    g_signal_emit (G_OBJECT (rtpdemux),
        gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE], 0, emit_pt);
  }

  if (rtpdemuxpad->newcaps) {
    GST_DEBUG ("need new caps");
    caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt);
    if (!caps)
      goto no_caps;

    caps = gst_caps_make_writable (caps);
    gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
    gst_pad_set_caps (srcpad, caps);
    gst_caps_unref (caps);
    rtpdemuxpad->newcaps = FALSE;
  }

  gst_buffer_set_caps (buf, GST_PAD_CAPS (srcpad));

  /* push to srcpad */
  ret = gst_pad_push (srcpad, buf);

  return ret;

  /* ERRORS */
invalid_buffer:
  {
    /* this is fatal and should be filtered earlier */
    GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL),
        ("Dropping invalid RTP payload"));
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
no_caps:
  {
    GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL),
        ("Could not get caps for payload"));
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
}
Example #14
0
static GstFlowReturn
gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
{
  GstFlowReturn ret = GST_FLOW_OK;
  GstRtpPtDemux *rtpdemux;
  guint8 pt;
  GstPad *srcpad;
  GstCaps *caps;
  GstRTPBuffer rtp = { NULL };

  rtpdemux = GST_RTP_PT_DEMUX (parent);

  if (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp))
    goto invalid_buffer;

  pt = gst_rtp_buffer_get_payload_type (&rtp);
  gst_rtp_buffer_unmap (&rtp);

  GST_DEBUG_OBJECT (rtpdemux, "received buffer for pt %d", pt);

  srcpad = find_pad_for_pt (rtpdemux, pt);
  if (srcpad == NULL) {
    /* new PT, create a src pad */
    GstRtpPtDemuxPad *rtpdemuxpad;
    GstElementClass *klass;
    GstPadTemplate *templ;
    gchar *padname;

    caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt);
    if (!caps)
      goto no_caps;

    klass = GST_ELEMENT_GET_CLASS (rtpdemux);
    templ = gst_element_class_get_pad_template (klass, "src_%u");
    padname = g_strdup_printf ("src_%u", pt);
    srcpad = gst_pad_new_from_template (templ, padname);
    gst_pad_use_fixed_caps (srcpad);
    g_free (padname);
    gst_pad_set_event_function (srcpad, gst_rtp_pt_demux_src_event);

    GST_DEBUG ("Adding pt=%d to the list.", pt);
    rtpdemuxpad = g_slice_new0 (GstRtpPtDemuxPad);
    rtpdemuxpad->pt = pt;
    rtpdemuxpad->newcaps = FALSE;
    rtpdemuxpad->pad = srcpad;
    gst_object_ref (srcpad);
    GST_OBJECT_LOCK (rtpdemux);
    rtpdemux->srcpads = g_slist_append (rtpdemux->srcpads, rtpdemuxpad);
    GST_OBJECT_UNLOCK (rtpdemux);

    gst_pad_set_active (srcpad, TRUE);


    /* First push the stream-start event, it must always come first */
    gst_pad_push_event (srcpad,
        gst_pad_get_sticky_event (rtpdemux->sink, GST_EVENT_STREAM_START, 0));

    /* Then caps event is sent */
    caps = gst_caps_make_writable (caps);
    gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
    gst_pad_set_caps (srcpad, caps);
    gst_caps_unref (caps);

    /* First sticky events on sink pad are forwarded to the new src pad */
    gst_pad_sticky_events_foreach (rtpdemux->sink, forward_sticky_events,
        srcpad);

    gst_element_add_pad (GST_ELEMENT_CAST (rtpdemux), srcpad);

    GST_DEBUG ("emitting new-payload-type for pt %d", pt);
    g_signal_emit (G_OBJECT (rtpdemux),
        gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE], 0, pt, srcpad);
  }

  if (pt != rtpdemux->last_pt) {
    gint emit_pt = pt;

    /* our own signal with an extra flag that this is the only pad */
    rtpdemux->last_pt = pt;
    GST_DEBUG ("emitting payload-type-changed for pt %d", emit_pt);
    g_signal_emit (G_OBJECT (rtpdemux),
        gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE], 0, emit_pt);
  }

  while (need_caps_for_pt (rtpdemux, pt)) {
    GST_DEBUG ("need new caps for %d", pt);
    caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt);
    if (!caps)
      goto no_caps;

    clear_newcaps_for_pt (rtpdemux, pt);

    caps = gst_caps_make_writable (caps);
    gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
    gst_pad_set_caps (srcpad, caps);
    gst_caps_unref (caps);
  }

  /* push to srcpad */
  ret = gst_pad_push (srcpad, buf);

  gst_object_unref (srcpad);

  return ret;

  /* ERRORS */
invalid_buffer:
  {
    /* this is fatal and should be filtered earlier */
    GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL),
        ("Dropping invalid RTP payload"));
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
no_caps:
  {
    GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL),
        ("Could not get caps for payload"));
    gst_buffer_unref (buf);
    if (srcpad)
      gst_object_unref (srcpad);
    return GST_FLOW_ERROR;
  }
}
static GstBuffer *
gst_rtp_ulpfec_dec_recover_from_fec (GstRtpUlpFecDec * self,
    RtpUlpFecMapInfo * info_fec, guint32 ssrc, gint media_pt, guint16 seq,
    guint8 * dst_pt)
{
  guint64 fec_mask = rtp_ulpfec_buffer_get_mask (&info_fec->rtp);
  gboolean fec_mask_long = rtp_ulpfec_buffer_get_fechdr (&info_fec->rtp)->L;
  guint16 fec_seq_base = rtp_ulpfec_buffer_get_seq_base (&info_fec->rtp);
  GstBuffer *ret;
  GList *it;

  g_array_set_size (self->scratch_buf, 0);
  rtp_buffer_to_ulpfec_bitstring (&info_fec->rtp, self->scratch_buf, TRUE,
      fec_mask_long);

  for (it = self->info_media; it; it = it->next) {
    RtpUlpFecMapInfo *info = RTP_FEC_MAP_INFO_NTH (self, it->data);
    guint64 packet_mask =
        rtp_ulpfec_packet_mask_from_seqnum (gst_rtp_buffer_get_seq (&info->rtp),
        fec_seq_base, TRUE);

    if (fec_mask & packet_mask) {
      fec_mask ^= packet_mask;
      rtp_buffer_to_ulpfec_bitstring (&info->rtp, self->scratch_buf, FALSE,
          fec_mask_long);
    }
  }

  ret =
      rtp_ulpfec_bitstring_to_media_rtp_buffer (self->scratch_buf,
      fec_mask_long, ssrc, seq);
  if (ret) {
    /* We are about to put recovered packet back in self->info_media to be able
     * to reuse it later for recovery of other packets
     **/
    gint i = self->info_arr->len;
    RtpUlpFecMapInfo *info;
    guint8 recovered_pt;

    g_array_set_size (self->info_arr, self->info_arr->len + 1);
    info = RTP_FEC_MAP_INFO_NTH (self, i);

    if (!rtp_ulpfec_map_info_map (gst_buffer_ref (ret), info)) {
      GST_WARNING_OBJECT (self, "Invalid recovered packet");
      goto recovered_packet_invalid;
    }

    recovered_pt = gst_rtp_buffer_get_payload_type (&info->rtp);
    if (!gst_rtp_ulpfec_dec_is_recovered_pt_valid (self, media_pt,
            recovered_pt)) {
      GST_WARNING_OBJECT (self,
          "Recovered packet has unexpected payload type (%u)", recovered_pt);
      goto recovered_packet_invalid;
    }

    GST_DEBUG_RTP_PACKET (self, "rtp header (recovered)", &info->rtp);
    self->info_media =
        g_list_insert_sorted_with_data (self->info_media, GUINT_TO_POINTER (i),
        _compare_fec_map_info, self);
    *dst_pt = recovered_pt;
  }
  return ret;

recovered_packet_invalid:
  g_array_set_size (self->info_arr, self->info_arr->len - 1);
  gst_buffer_unref (ret);
  return NULL;
}
static GstFlowReturn
gst_rtp_dec_chain_rtp (GstPad * pad, GstObject * parent, GstBuffer * buffer)
{
    GstFlowReturn res;
    GstRTPDec *rtpdec;
    GstRTPDecSession *session;
    guint32 ssrc;
    guint8 pt;
    GstRTPBuffer rtp = { NULL, };

    rtpdec = GST_RTP_DEC (parent);

    GST_DEBUG_OBJECT (rtpdec, "got rtp packet");

    if (!gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp))
        goto bad_packet;

    ssrc = gst_rtp_buffer_get_ssrc (&rtp);
    pt = gst_rtp_buffer_get_payload_type (&rtp);
    gst_rtp_buffer_unmap (&rtp);

    GST_DEBUG_OBJECT (rtpdec, "SSRC %08x, PT %d", ssrc, pt);

    /* find session */
    session = gst_pad_get_element_private (pad);

    /* see if we have the pad */
    if (!session->active) {
        GstPadTemplate *templ;
        GstElementClass *klass;
        gchar *name;
        GstCaps *caps;
        GValue ret = { 0 };
        GValue args[3] = { {0}
            , {0}
            , {0}
        };

        GST_DEBUG_OBJECT (rtpdec, "creating stream");

        session->ssrc = ssrc;
        session->pt = pt;

        /* get pt map */
        g_value_init (&args[0], GST_TYPE_ELEMENT);
        g_value_set_object (&args[0], rtpdec);
        g_value_init (&args[1], G_TYPE_UINT);
        g_value_set_uint (&args[1], session->id);
        g_value_init (&args[2], G_TYPE_UINT);
        g_value_set_uint (&args[2], pt);

        g_value_init (&ret, GST_TYPE_CAPS);
        g_value_set_boxed (&ret, NULL);

        g_signal_emitv (args, gst_rtp_dec_signals[SIGNAL_REQUEST_PT_MAP], 0, &ret);

        caps = (GstCaps *) g_value_get_boxed (&ret);

        name = g_strdup_printf ("recv_rtp_src_%u_%u_%u", session->id, ssrc, pt);
        klass = GST_ELEMENT_GET_CLASS (rtpdec);
        templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%u_%u_%u");
        session->recv_rtp_src = gst_pad_new_from_template (templ, name);
        g_free (name);

        gst_pad_set_caps (session->recv_rtp_src, caps);

        gst_pad_set_element_private (session->recv_rtp_src, session);
        gst_pad_set_query_function (session->recv_rtp_src, gst_rtp_dec_query_src);
        gst_pad_set_active (session->recv_rtp_src, TRUE);
        gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_src);

        session->active = TRUE;
    }

    res = gst_pad_push (session->recv_rtp_src, buffer);

    return res;

bad_packet:
    {
        GST_ELEMENT_WARNING (rtpdec, STREAM, DECODE, (NULL),
                             ("RTP packet did not validate, dropping"));
        gst_buffer_unref (buffer);
        return GST_FLOW_OK;
    }
}
static GstFlowReturn
gst_rtp_rtx_receive_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
{
  GstRtpRtxReceive *rtx = GST_RTP_RTX_RECEIVE (parent);
  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
  GstFlowReturn ret = GST_FLOW_OK;
  GstBuffer *new_buffer = NULL;
  guint32 ssrc = 0;
  gpointer ssrc1 = 0;
  guint32 ssrc2 = 0;
  guint16 seqnum = 0;
  guint16 orign_seqnum = 0;
  guint8 payload_type = 0;
  guint8 origin_payload_type = 0;
  gboolean is_rtx;
  gboolean drop = FALSE;

  /* map current rtp packet to parse its header */
  gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp);
  ssrc = gst_rtp_buffer_get_ssrc (&rtp);
  seqnum = gst_rtp_buffer_get_seq (&rtp);
  payload_type = gst_rtp_buffer_get_payload_type (&rtp);

  /* check if we have a retransmission packet (this information comes from SDP) */
  GST_OBJECT_LOCK (rtx);

  rtx->last_time = GST_BUFFER_PTS (buffer);

  if (g_hash_table_size (rtx->seqnum_ssrc1_map) > 0) {
    GHashTableIter iter;
    gpointer key, value;

    g_hash_table_iter_init (&iter, rtx->seqnum_ssrc1_map);
    while (g_hash_table_iter_next (&iter, &key, &value)) {
      SsrcAssoc *assoc = value;

      /* remove association request if it is too old */
      if (GST_CLOCK_TIME_IS_VALID (rtx->last_time) &&
          GST_CLOCK_TIME_IS_VALID (assoc->time) &&
          assoc->time + ASSOC_TIMEOUT < rtx->last_time) {
        g_hash_table_iter_remove (&iter);
      }
    }
  }

  is_rtx =
      g_hash_table_lookup_extended (rtx->rtx_pt_map,
      GUINT_TO_POINTER (payload_type), NULL, NULL);

  /* if the current packet is from a retransmission stream */
  if (is_rtx) {
    /* increase our statistic */
    ++rtx->num_rtx_packets;

    /* read OSN in the rtx payload */
    orign_seqnum = GST_READ_UINT16_BE (gst_rtp_buffer_get_payload (&rtp));
    origin_payload_type =
        GPOINTER_TO_UINT (g_hash_table_lookup (rtx->rtx_pt_map,
            GUINT_TO_POINTER (payload_type)));

    /* first we check if we already have associated this retransmission stream
     * to a master stream */
    if (g_hash_table_lookup_extended (rtx->ssrc2_ssrc1_map,
            GUINT_TO_POINTER (ssrc), NULL, &ssrc1)) {
      GST_DEBUG_OBJECT (rtx,
          "packet is from retransmission stream %" G_GUINT32_FORMAT
          " already associated to master stream %" G_GUINT32_FORMAT, ssrc,
          GPOINTER_TO_UINT (ssrc1));
      ssrc2 = ssrc;
    } else {
      SsrcAssoc *assoc;

      /* the current retransmitted packet has its rtx stream not already
       * associated to a master stream, so retrieve it from our request
       * history */
      if (g_hash_table_lookup_extended (rtx->seqnum_ssrc1_map,
              GUINT_TO_POINTER (orign_seqnum), NULL, (gpointer *) & assoc)) {
        GST_DEBUG_OBJECT (rtx,
            "associate retransmitted stream %" G_GUINT32_FORMAT
            " to master stream %" G_GUINT32_FORMAT " thanks to packet %"
            G_GUINT16_FORMAT "", ssrc, assoc->ssrc, orign_seqnum);
        ssrc1 = GUINT_TO_POINTER (assoc->ssrc);
        ssrc2 = ssrc;

        /* just put a guard */
        if (GPOINTER_TO_UINT (ssrc1) == ssrc2)
          GST_WARNING_OBJECT (rtx, "RTX receiver ssrc2_ssrc1_map bad state, "
              "ssrc %" G_GUINT32_FORMAT " are the same\n", ssrc);

        /* free the spot so that this seqnum can be used to do another
         * association */
        g_hash_table_remove (rtx->seqnum_ssrc1_map,
            GUINT_TO_POINTER (orign_seqnum));

        /* actually do the association between rtx stream and master stream */
        g_hash_table_insert (rtx->ssrc2_ssrc1_map, GUINT_TO_POINTER (ssrc2),
            ssrc1);

        /* also do the association between master stream and rtx stream
         * every ssrc are unique so we can use the same hash table
         * for both retrieving the ssrc1 from ssrc2 and also ssrc2 from ssrc1
         */
        g_hash_table_insert (rtx->ssrc2_ssrc1_map, ssrc1,
            GUINT_TO_POINTER (ssrc2));

      } else {
        /* we are not able to associate this rtx packet with a master stream */
        GST_DEBUG_OBJECT (rtx,
            "drop rtx packet because its orign_seqnum %" G_GUINT16_FORMAT
            " is not in pending retransmission requests", orign_seqnum);
        drop = TRUE;
      }
    }
  }

  /* if not dropped the packet was successfully associated */
  if (is_rtx && !drop)
    ++rtx->num_rtx_assoc_packets;

  GST_OBJECT_UNLOCK (rtx);

  /* just drop the packet if the association could not have been made */
  if (drop) {
    gst_rtp_buffer_unmap (&rtp);
    gst_buffer_unref (buffer);
    return GST_FLOW_OK;
  }

  /* create the retransmission packet */
  if (is_rtx)
    new_buffer =
        _gst_rtp_buffer_new_from_rtx (&rtp, GPOINTER_TO_UINT (ssrc1),
        orign_seqnum, origin_payload_type);

  gst_rtp_buffer_unmap (&rtp);

  /* push the packet */
  if (is_rtx) {
    gst_buffer_unref (buffer);
    GST_LOG_OBJECT (rtx, "push packet seqnum:%" G_GUINT16_FORMAT
        " from a restransmission stream ssrc2:%" G_GUINT32_FORMAT " (src %"
        G_GUINT32_FORMAT ")", orign_seqnum, ssrc2, GPOINTER_TO_UINT (ssrc1));
    ret = gst_pad_push (rtx->srcpad, new_buffer);
  } else {
    GST_LOG_OBJECT (rtx, "push packet seqnum:%" G_GUINT16_FORMAT
        " from a master stream ssrc: %" G_GUINT32_FORMAT, seqnum, ssrc);
    ret = gst_pad_push (rtx->srcpad, buffer);
  }

  return ret;
}