static void kms_rtp_synchronizer_process_rtcp_packet (KmsRtpSynchronizer * self, GstRTCPPacket * packet, GstClockTime current_time) { GstRTCPType type; guint32 ssrc, rtp_time; guint64 ntp_time, ntp_ns_time; type = gst_rtcp_packet_get_type (packet); GST_DEBUG_OBJECT (self, "Received RTCP buffer of type: %d", type); if (type != GST_RTCP_TYPE_SR) { return; } gst_rtcp_packet_sr_get_sender_info (packet, &ssrc, &ntp_time, &rtp_time, NULL, NULL); /* convert ntp_time to nanoseconds */ ntp_ns_time = gst_util_uint64_scale (ntp_time, GST_SECOND, (G_GINT64_CONSTANT (1) << 32)); KMS_RTP_SYNCHRONIZER_LOCK (self); GST_DEBUG_OBJECT (self, "Received RTCP SR packet SSRC: %u, rtp_time: %u, ntp_time: %" G_GUINT64_FORMAT ", ntp_ns_time: %" GST_TIME_FORMAT, ssrc, rtp_time, ntp_time, GST_TIME_ARGS (ntp_ns_time)); if (!self->priv->base_initiated) { kms_rtp_sync_context_get_time_matching (self->priv->context, ntp_ns_time, current_time, &self->priv->base_ntp_ns_time, &self->priv->base_sync_time); self->priv->base_initiated = TRUE; } self->priv->last_sr_ext_ts = gst_rtp_buffer_ext_timestamp (&self->priv->ext_ts, rtp_time); self->priv->last_sr_ntp_ns_time = ntp_ns_time; KMS_RTP_SYNCHRONIZER_UNLOCK (self); }
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; } }
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; } }
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; }