static GstBuffer * create_rtcp_app (guint32 ssrc, guint count) { GInetAddress *inet_addr_0; guint16 port = 5678 + count; GSocketAddress *socket_addr_0; GstBuffer *rtcp_buffer; GstRTCPPacket *rtcp_packet = NULL; GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT; inet_addr_0 = g_inet_address_new_from_string ("192.168.1.1"); socket_addr_0 = g_inet_socket_address_new (inet_addr_0, port); g_object_unref (inet_addr_0); rtcp_buffer = gst_rtcp_buffer_new (1400); gst_buffer_add_net_address_meta (rtcp_buffer, socket_addr_0); g_object_unref (socket_addr_0); /* need to begin with rr */ gst_rtcp_buffer_map (rtcp_buffer, GST_MAP_READWRITE, &rtcp); rtcp_packet = g_slice_new0 (GstRTCPPacket); gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_RR, rtcp_packet); gst_rtcp_packet_rr_set_ssrc (rtcp_packet, ssrc); g_slice_free (GstRTCPPacket, rtcp_packet); /* useful to make the rtcp buffer valid */ rtcp_packet = g_slice_new0 (GstRTCPPacket); gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_APP, rtcp_packet); g_slice_free (GstRTCPPacket, rtcp_packet); gst_rtcp_buffer_unmap (&rtcp); return rtcp_buffer; }
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 GstBuffer * make_buffer (gboolean have_sr, gint rr_count, gboolean have_sdes, gboolean have_bye) { GstRTCPPacket packet; GstBuffer *buf = gst_rtcp_buffer_new (1024); gint i; GstRTCPBuffer rtcpbuffer = GST_RTCP_BUFFER_INIT; gst_rtcp_buffer_map (buf, GST_MAP_READWRITE, &rtcpbuffer); if (have_sr) { gst_rtcp_buffer_add_packet (&rtcpbuffer, GST_RTCP_TYPE_SR, &packet); gst_rtcp_packet_sr_set_sender_info (&packet, 132132, 12, 12, 12, 12); } if (rr_count >= 0 || !have_sr) { gst_rtcp_buffer_add_packet (&rtcpbuffer, GST_RTCP_TYPE_RR, &packet); gst_rtcp_packet_rr_set_ssrc (&packet, 132132); for (i = 0; i < rr_count; i++) gst_rtcp_packet_add_rb (&packet, 123124+i, 12, 12, 21, 31, 41, 12); } if (have_sdes) { gst_rtcp_buffer_add_packet (&rtcpbuffer, GST_RTCP_TYPE_SDES, &packet); gst_rtcp_packet_sdes_add_item (&packet, 123121); gst_rtcp_packet_sdes_add_entry (&packet, GST_RTCP_SDES_EMAIL, 10, (guint8 *) "*****@*****.**"); gst_rtcp_packet_sdes_add_entry (&packet, GST_RTCP_SDES_CNAME, 10, (guint8 *) "*****@*****.**"); gst_rtcp_packet_sdes_add_entry (&packet, GST_RTCP_SDES_PHONE, 10, (guint8 *) "11-21-2-11"); } if (have_bye) { gst_rtcp_buffer_add_packet (&rtcpbuffer, GST_RTCP_TYPE_BYE, &packet); gst_rtcp_packet_bye_add_ssrc (&packet, 132123); gst_rtcp_packet_bye_set_reason (&packet, "allo"); } gst_rtcp_buffer_unmap (&rtcpbuffer); return buf; }
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_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 void on_sending_rtcp (GObject * sess, GstBuffer * buffer, gboolean is_early, gboolean * do_not_supress) { KmsRembLocal *rl; KmsRTCPPSFBAFBREMBPacket remb_packet; GstRTCPBuffer rtcp = { NULL, }; GstRTCPPacket packet; guint packet_ssrc; rl = g_object_get_data (sess, KMS_REMB_LOCAL); if (!rl) { GST_WARNING ("Invalid RembLocal"); return; } if (is_early) { return; } if (!gst_rtcp_buffer_map (buffer, GST_MAP_READWRITE, &rtcp)) { GST_WARNING_OBJECT (sess, "Cannot map buffer to RTCP"); return; } if (!gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_PSFB, &packet)) { GST_WARNING_OBJECT (sess, "Cannot add RTCP packet"); goto end; } if (!kms_remb_local_update (rl)) { goto end; } remb_packet.bitrate = rl->remb; if (rl->event_manager != NULL) { guint remb_local_max; remb_local_max = kms_utils_remb_event_manager_get_min (rl->event_manager); if (remb_local_max > 0) { GST_TRACE_OBJECT (sess, "REMB local max: %" G_GUINT32_FORMAT, remb_local_max); remb_packet.bitrate = MIN (remb_local_max, rl->remb); } } if (rl->min_bw > 0) { remb_packet.bitrate = MAX (remb_packet.bitrate, rl->min_bw * 1000); } else { remb_packet.bitrate = MAX (remb_packet.bitrate, REMB_MIN); } remb_packet.n_ssrcs = 1; remb_packet.ssrcs[0] = rl->remote_ssrc; g_object_get (sess, "internal-ssrc", &packet_ssrc, NULL); if (!kms_rtcp_psfb_afb_remb_marshall_packet (&packet, &remb_packet, packet_ssrc)) { gst_rtcp_packet_remove (&packet); } GST_TRACE_OBJECT (sess, "Sending REMB (bitrate: %" G_GUINT32_FORMAT ", ssrc: %" G_GUINT32_FORMAT ")", remb_packet.bitrate, rl->remote_ssrc); kms_remb_base_update_stats (KMS_REMB_BASE (rl), rl->remote_ssrc, remb_packet.bitrate); end: gst_rtcp_buffer_unmap (&rtcp); }
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; }