gboolean
kms_rtp_synchronizer_process_rtcp_buffer (KmsRtpSynchronizer * self,
    GstBuffer * buffer, GstClockTime current_time, GError ** error)
{
  GstRTCPBuffer rtcp_buffer = GST_RTCP_BUFFER_INIT;
  GstRTCPPacket packet;

  if (!gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp_buffer)) {
    const gchar *msg = "Buffer cannot be mapped as RTCP";

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

    return FALSE;
  }

  if (!gst_rtcp_buffer_get_first_packet (&rtcp_buffer, &packet)) {
    GST_WARNING_OBJECT (self, "Empty RTCP buffer");
    goto unmap;
  }

  kms_rtp_synchronizer_process_rtcp_packet (self, &packet, current_time);

unmap:
  gst_rtcp_buffer_unmap (&rtcp_buffer);

  return TRUE;
}
static gboolean
refresh_rtcp_rr_ssrcs_map (KmsRtcpDemux * rtcpdemux, GstBuffer * buffer)
{
  GstRTCPBuffer rtcp = { NULL, };
  GstRTCPPacket packet;
  GstRTCPType type;
  gboolean ret = TRUE;
  guint32 remote_ssrc, local_ssrc;

  gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp);

  if (!gst_rtcp_buffer_get_first_packet (&rtcp, &packet)) {
    ret = FALSE;
    goto end;
  }

  type = gst_rtcp_packet_get_type (&packet);

  if (type != GST_RTCP_TYPE_RR) {
    ret = TRUE;
    goto end;
  }

  remote_ssrc = gst_rtcp_packet_rr_get_ssrc (&packet);
  ret =
      g_hash_table_contains (rtcpdemux->priv->rr_ssrcs,
      GUINT_TO_POINTER (remote_ssrc));

  if (!ret && (gst_rtcp_packet_get_rb_count (&packet) > 0)) {
    gst_rtcp_packet_get_rb (&packet, 0, &local_ssrc, NULL, NULL, NULL, NULL,
        NULL, NULL);
    GST_TRACE_OBJECT (rtcpdemux, "remote_ssrc (%u) - local_ssrc(%u)",
        remote_ssrc, local_ssrc);
    g_hash_table_insert (rtcpdemux->priv->rr_ssrcs,
        GUINT_TO_POINTER (remote_ssrc), GUINT_TO_POINTER (local_ssrc));
    ret = TRUE;
  }

end:
  gst_rtcp_buffer_unmap (&rtcp);

  return ret;
}
static GstFlowReturn
gst_rdt_manager_chain_rtcp (GstPad * pad, GstObject * parent,
    GstBuffer * buffer)
{
  GstRDTManager *src;

#ifdef HAVE_RTCP
  gboolean valid;
  GstRTCPPacket packet;
  gboolean more;
#endif

  src = GST_RDT_MANAGER (parent);

  GST_DEBUG_OBJECT (src, "got rtcp packet");

#ifdef HAVE_RTCP
  valid = gst_rtcp_buffer_validate (buffer);
  if (!valid)
    goto bad_packet;

  /* position on first packet */
  more = gst_rtcp_buffer_get_first_packet (buffer, &packet);
  while (more) {
    switch (gst_rtcp_packet_get_type (&packet)) {
      case GST_RTCP_TYPE_SR:
      {
        guint32 ssrc, rtptime, packet_count, octet_count;
        guint64 ntptime;
        guint count, i;

        gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, &ntptime, &rtptime,
            &packet_count, &octet_count);

        GST_DEBUG_OBJECT (src,
            "got SR packet: SSRC %08x, NTP %" G_GUINT64_FORMAT
            ", RTP %u, PC %u, OC %u", ssrc, ntptime, rtptime, packet_count,
            octet_count);

        count = gst_rtcp_packet_get_rb_count (&packet);
        for (i = 0; i < count; i++) {
          guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
          guint8 fractionlost;
          gint32 packetslost;

          gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
              &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);

          GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
              ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
              packetslost, exthighestseq, jitter, lsr, dlsr);
        }
        break;
      }
      case GST_RTCP_TYPE_RR:
      {
        guint32 ssrc;
        guint count, i;

        ssrc = gst_rtcp_packet_rr_get_ssrc (&packet);

        GST_DEBUG_OBJECT (src, "got RR packet: SSRC %08x", ssrc);

        count = gst_rtcp_packet_get_rb_count (&packet);
        for (i = 0; i < count; i++) {
          guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
          guint8 fractionlost;
          gint32 packetslost;

          gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
              &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);

          GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
              ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
              packetslost, exthighestseq, jitter, lsr, dlsr);
        }
        break;
      }
      case GST_RTCP_TYPE_SDES:
      {
        guint chunks, i, j;
        gboolean more_chunks, more_items;

        chunks = gst_rtcp_packet_sdes_get_chunk_count (&packet);
        GST_DEBUG_OBJECT (src, "got SDES packet with %d chunks", chunks);

        more_chunks = gst_rtcp_packet_sdes_first_chunk (&packet);
        i = 0;
        while (more_chunks) {
          guint32 ssrc;

          ssrc = gst_rtcp_packet_sdes_get_ssrc (&packet);

          GST_DEBUG_OBJECT (src, "chunk %d, SSRC %08x", i, ssrc);

          more_items = gst_rtcp_packet_sdes_first_item (&packet);
          j = 0;
          while (more_items) {
            GstRTCPSDESType type;
            guint8 len;
            gchar *data;

            gst_rtcp_packet_sdes_get_item (&packet, &type, &len, &data);

            GST_DEBUG_OBJECT (src, "item %d, type %d, len %d, data %s", j,
                type, len, data);

            more_items = gst_rtcp_packet_sdes_next_item (&packet);
            j++;
          }
          more_chunks = gst_rtcp_packet_sdes_next_chunk (&packet);
          i++;
        }
        break;
      }
      case GST_RTCP_TYPE_BYE:
      {
        guint count, i;
        gchar *reason;

        reason = gst_rtcp_packet_bye_get_reason (&packet);
        GST_DEBUG_OBJECT (src, "got BYE packet (reason: %s)",
            GST_STR_NULL (reason));
        g_free (reason);

        count = gst_rtcp_packet_bye_get_ssrc_count (&packet);
        for (i = 0; i < count; i++) {
          guint32 ssrc;


          ssrc = gst_rtcp_packet_bye_get_nth_ssrc (&packet, i);

          GST_DEBUG_OBJECT (src, "SSRC: %08x", ssrc);
        }
        break;
      }
      case GST_RTCP_TYPE_APP:
        GST_DEBUG_OBJECT (src, "got APP packet");
        break;
      default:
        GST_WARNING_OBJECT (src, "got unknown RTCP packet");
        break;
    }
    more = gst_rtcp_packet_move_to_next (&packet);
  }
  gst_buffer_unref (buffer);
  return GST_FLOW_OK;

bad_packet:
  {
    GST_WARNING_OBJECT (src, "got invalid RTCP packet");
    return GST_FLOW_OK;
  }
#else
  return GST_FLOW_OK;
#endif
}
static GstFlowReturn
gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad, GstObject * parent,
                               GstBuffer * buf)
{
    GstFlowReturn ret;
    GstRtpSsrcDemux *demux;
    guint32 ssrc;
    GstRTCPPacket packet;
    GstRTCPBuffer rtcp = { NULL, };
    GstPad *srcpad;
    GstRtpSsrcDemuxPad *dpad;

    demux = GST_RTP_SSRC_DEMUX (parent);

    if (!gst_rtcp_buffer_validate_reduced (buf))
        goto invalid_rtcp;

    gst_rtcp_buffer_map (buf, GST_MAP_READ, &rtcp);
    if (!gst_rtcp_buffer_get_first_packet (&rtcp, &packet)) {
        gst_rtcp_buffer_unmap (&rtcp);
        goto invalid_rtcp;
    }

    /* first packet must be SR or RR, or in case of a reduced size RTCP packet
     * it must be APP, RTPFB or PSFB feeadback, or else the validate would
     * have failed */
    switch (gst_rtcp_packet_get_type (&packet)) {
    case GST_RTCP_TYPE_SR:
        /* get the ssrc so that we can route it to the right source pad */
        gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, NULL, NULL, NULL,
                                            NULL);
        break;
    case GST_RTCP_TYPE_RR:
        ssrc = gst_rtcp_packet_rr_get_ssrc (&packet);
        break;
    case GST_RTCP_TYPE_APP:
    case GST_RTCP_TYPE_RTPFB:
    case GST_RTCP_TYPE_PSFB:
        ssrc = gst_rtcp_packet_fb_get_sender_ssrc (&packet);
        break;
    default:
        goto unexpected_rtcp;
    }
    gst_rtcp_buffer_unmap (&rtcp);

    GST_DEBUG_OBJECT (demux, "received RTCP of SSRC %08x", ssrc);

    srcpad = find_or_create_demux_pad_for_ssrc (demux, ssrc, RTCP_PAD);
    if (srcpad == NULL)
        goto create_failed;

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

    if (ret != GST_FLOW_OK) {
        /* check if the ssrc still there, may have been removed */
        GST_PAD_LOCK (demux);
        dpad = find_demux_pad_for_ssrc (demux, ssrc);
        if (dpad == NULL || dpad->rtcp_pad != srcpad) {
            /* SSRC was removed during the push ... ignore the error */
            ret = GST_FLOW_OK;
        }
        GST_PAD_UNLOCK (demux);
    }

    gst_object_unref (srcpad);

    return ret;

    /* ERRORS */
invalid_rtcp:
    {
        /* this is fatal and should be filtered earlier */
        GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
                           ("Dropping invalid RTCP packet"));
        gst_buffer_unref (buf);
        return GST_FLOW_ERROR;
    }
unexpected_rtcp:
    {
        GST_DEBUG_OBJECT (demux, "dropping unexpected RTCP packet");
        gst_buffer_unref (buf);
        return GST_FLOW_OK;
    }
create_failed:
    {
        GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
                           ("Could not create new pad"));
        gst_buffer_unref (buf);
        return GST_FLOW_ERROR;
    }
}
Exemple #5
0
static GstFlowReturn
gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad, GstObject * parent,
    GstBuffer * buf)
{
  GstFlowReturn ret;
  GstRtpSsrcDemux *demux;
  guint32 ssrc;
  GstRtpSsrcDemuxPad *dpad;
  GstRTCPPacket packet;
  GstRTCPBuffer rtcp = { NULL, };
  GstPad *srcpad;

  demux = GST_RTP_SSRC_DEMUX (parent);

  if (!gst_rtcp_buffer_validate (buf))
    goto invalid_rtcp;

  gst_rtcp_buffer_map (buf, GST_MAP_READ, &rtcp);
  if (!gst_rtcp_buffer_get_first_packet (&rtcp, &packet)) {
    gst_rtcp_buffer_unmap (&rtcp);
    goto invalid_rtcp;
  }

  /* first packet must be SR or RR or else the validate would have failed */
  switch (gst_rtcp_packet_get_type (&packet)) {
    case GST_RTCP_TYPE_SR:
      /* get the ssrc so that we can route it to the right source pad */
      gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, NULL, NULL, NULL,
          NULL);
      break;
    default:
      goto unexpected_rtcp;
  }
  gst_rtcp_buffer_unmap (&rtcp);

  GST_DEBUG_OBJECT (demux, "received RTCP of SSRC %08x", ssrc);

  GST_PAD_LOCK (demux);
  dpad = find_or_create_demux_pad_for_ssrc (demux, ssrc);
  if (dpad == NULL) {
    GST_PAD_UNLOCK (demux);
    goto create_failed;
  }
  srcpad = gst_object_ref (dpad->rtcp_pad);
  GST_PAD_UNLOCK (demux);

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

  gst_object_unref (srcpad);

  return ret;

  /* ERRORS */
invalid_rtcp:
  {
    /* this is fatal and should be filtered earlier */
    GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
        ("Dropping invalid RTCP packet"));
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
unexpected_rtcp:
  {
    GST_DEBUG_OBJECT (demux, "dropping unexpected RTCP packet");
    gst_buffer_unref (buf);
    return GST_FLOW_OK;
  }
create_failed:
  {
    GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
        ("Could not create new pad"));
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
}
Exemple #6
0
static GstFlowReturn
fs_rtcp_filter_transform_ip (GstBaseTransform *transform, GstBuffer *buf)
{
    FsRtcpFilter *filter = FS_RTCP_FILTER (transform);

    if (!gst_rtcp_buffer_validate (buf))
    {
        GST_ERROR_OBJECT (transform, "Invalid RTCP buffer");
        return GST_FLOW_ERROR;
    }

    GST_OBJECT_LOCK (filter);

    if (!filter->sending)
    {
        GstRTCPBuffer rtcpbuffer = GST_RTCP_BUFFER_INIT;
        GstRTCPPacket packet;

        gst_rtcp_buffer_map (buf, GST_MAP_READWRITE, &rtcpbuffer);

        if (gst_rtcp_buffer_get_first_packet (&rtcpbuffer, &packet))
        {
            for (;;)
            {
                if (gst_rtcp_packet_get_type (&packet) == GST_RTCP_TYPE_SR)
                {
                    GstRTCPPacket nextpacket = packet;

                    if (gst_rtcp_packet_move_to_next (&nextpacket) &&
                            gst_rtcp_packet_get_type (&nextpacket) == GST_RTCP_TYPE_RR)
                    {
                        if (!gst_rtcp_packet_remove (&packet))
                            break;
                    }
                    else
                    {
                        guchar *data = rtcpbuffer.map.data + packet.offset;

                        /* If there is no RR, lets add an empty one */
                        data[0] = (GST_RTCP_VERSION << 6);
                        data[1] = GST_RTCP_TYPE_RR;
                        data[2] = 0;
                        data[3] = 1;
                        memmove (rtcpbuffer.map.data + packet.offset + 8,
                                 rtcpbuffer.map.data + nextpacket.offset,
                                 rtcpbuffer.map.size - nextpacket.offset);

                        rtcpbuffer.map.size -= nextpacket.offset - packet.offset - 8 ;

                        if (!gst_rtcp_buffer_get_first_packet (&rtcpbuffer, &packet))
                            break;
                    }

                }
                else
                {
                    if (!gst_rtcp_packet_move_to_next (&packet))
                        break;
                }
            }
        }
        gst_rtcp_buffer_unmap (&rtcpbuffer);
    }

    GST_OBJECT_UNLOCK (filter);

    return GST_FLOW_OK;
}