From c3448f978e16e29cc92133edcaea2c9285d35277 Mon Sep 17 00:00:00 2001 From: Pascal Buhler Date: Mon, 31 Aug 2009 18:42:25 +0200 Subject: [PATCH] rtpmanager: improve SDES handling Store SDES internally as a struct to support multiple PRIV values. Include all values set in SDES struct when sending RTCP SDES. --- gst/rtpmanager/rtpsession.c | 87 +++++++++++++--- gst/rtpmanager/rtpsource.c | 235 +++++++++++++++----------------------------- gst/rtpmanager/rtpsource.h | 10 +- 3 files changed, 151 insertions(+), 181 deletions(-) diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c index e3eae0f..898d59d 100644 --- a/gst/rtpmanager/rtpsession.c +++ b/gst/rtpmanager/rtpsession.c @@ -1669,6 +1669,7 @@ rtp_session_process_sdes (RTPSession * sess, GstRTCPPacket * packet, guint32 ssrc; gboolean changed, created; RTPSource *source; + GstStructure *sdes; ssrc = gst_rtcp_packet_sdes_get_ssrc (packet); @@ -1681,24 +1682,45 @@ rtp_session_process_sdes (RTPSession * sess, GstRTCPPacket * packet, if (!source) return; + sdes = gst_structure_new ("application/x-rtp-source-sdes", NULL); + more_entries = gst_rtcp_packet_sdes_first_entry (packet); j = 0; while (more_entries) { GstRTCPSDESType type; guint8 len; guint8 *data; + gchar *name; + gchar *value; gst_rtcp_packet_sdes_get_entry (packet, &type, &len, &data); GST_DEBUG ("entry %d, type %d, len %d, data %.*s", j, type, len, len, data); - changed |= rtp_source_set_sdes (source, type, data, len); + if (type == GST_RTCP_SDES_PRIV) { + name = g_strndup ((const gchar *) &data[1], data[0]); + len -= data[0] + 1; + data += data[0] + 1; + } else { + name = g_strdup (gst_rtcp_sdes_type_to_name (type)); + } + + value = g_strndup ((const gchar *) data, len); + + gst_structure_set (sdes, name, G_TYPE_STRING, value, NULL); + + g_free (name); + g_free (value); more_entries = gst_rtcp_packet_sdes_next_entry (packet); j++; } + changed = rtp_source_set_sdes_struct (source, sdes); + + gst_structure_free (sdes); + source->validated = TRUE; if (created) @@ -2296,27 +2318,60 @@ static void session_sdes (RTPSession * sess, ReportData * data) { GstRTCPPacket *packet = &data->packet; - guint8 *sdes_data; - guint sdes_len; + GstStructure *sdes; + gint i, n_fields; /* add SDES packet */ gst_rtcp_buffer_add_packet (data->rtcp, GST_RTCP_TYPE_SDES, packet); gst_rtcp_packet_sdes_add_item (packet, sess->source->ssrc); - rtp_source_get_sdes (sess->source, GST_RTCP_SDES_CNAME, &sdes_data, - &sdes_len); - gst_rtcp_packet_sdes_add_entry (packet, GST_RTCP_SDES_CNAME, sdes_len, - sdes_data); - - /* other SDES items must only be added at regular intervals and only when the - * user requests to since it might be a privacy problem */ -#if 0 - gst_rtcp_packet_sdes_add_entry (&packet, GST_RTCP_SDES_NAME, - strlen (sess->name), (guint8 *) sess->name); - gst_rtcp_packet_sdes_add_entry (&packet, GST_RTCP_SDES_TOOL, - strlen (sess->tool), (guint8 *) sess->tool); -#endif + sdes = rtp_source_get_sdes_struct (sess->source); + + /* add all fields in the structure, the order is not important. */ + n_fields = gst_structure_n_fields (sdes); + for (i = 0; i < n_fields; ++i) { + const gchar *field; + const gchar *value; + GstRTCPSDESType type; + + field = gst_structure_nth_field_name (sdes, i); + if (field == NULL) + continue; + value = gst_structure_get_string (sdes, field); + if (value == NULL) + continue; + type = gst_rtcp_sdes_name_to_type (field); + + if (type > GST_RTCP_SDES_END && type < GST_RTCP_SDES_PRIV) { + gst_rtcp_packet_sdes_add_entry (packet, type, strlen (value), + (const guint8 *) value); + } else if (type == GST_RTCP_SDES_PRIV) { + gsize prefix_len; + gsize value_len; + gsize data_len; + guint8 data[256]; + + /* don't accept entries that are too big */ + prefix_len = strlen (field); + if (prefix_len > 255) + continue; + value_len = strlen (value); + if (value_len > 255) + continue; + data_len = 1 + prefix_len + value_len; + if (data_len > 255) + continue; + + data[0] = prefix_len; + memcpy (&data[1], field, prefix_len); + memcpy (&data[1 + prefix_len], value, value_len); + + gst_rtcp_packet_sdes_add_entry (packet, type, data_len, data); + } + } + + gst_structure_free (sdes); data->has_sdes = TRUE; } diff --git a/gst/rtpmanager/rtpsource.c b/gst/rtpmanager/rtpsource.c index 03e5ae5..e6f8bef 100644 --- a/gst/rtpmanager/rtpsource.c +++ b/gst/rtpmanager/rtpsource.c @@ -98,16 +98,19 @@ rtp_source_class_init (RTPSourceClass * klass) /** * RTPSource::sdes * - * The current SDES items of the source. Returns a structure with the - * following fields: + * The current SDES items of the source. Returns a structure with name + * application/x-rtp-source-sdes and may contain the following fields: * - * 'cname' G_TYPE_STRING : The canonical name - * 'name' G_TYPE_STRING : The user name - * 'email' G_TYPE_STRING : The user's electronic mail address - * 'phone' G_TYPE_STRING : The user's phone number - * 'location' G_TYPE_STRING : The geographic user location - * 'tool' G_TYPE_STRING : The name of application or tool - * 'note' G_TYPE_STRING : A notice about the source + * 'cname' G_TYPE_STRING : The canonical name + * 'name' G_TYPE_STRING : The user name + * 'email' G_TYPE_STRING : The user's electronic mail address + * 'phone' G_TYPE_STRING : The user's phone number + * 'location' G_TYPE_STRING : The geographic user location + * 'tool' G_TYPE_STRING : The name of application or tool + * 'note' G_TYPE_STRING : A notice about the source + * + * other fields may be present and these represent private items in + * the SDES where the field name is the prefix. */ g_object_class_install_property (gobject_class, PROP_SDES, g_param_spec_boxed ("sdes", "SDES", @@ -156,6 +159,8 @@ rtp_source_init (RTPSource * src) src->internal = FALSE; src->probation = RTP_DEFAULT_PROBATION; + src->sdes = gst_structure_new ("application/x-rtp-source-sdes", NULL); + src->payload = -1; src->clock_rate = -1; src->packets = g_queue_new (); @@ -170,7 +175,6 @@ rtp_source_finalize (GObject * object) { RTPSource *src; GstBuffer *buffer; - gint i; src = RTP_SOURCE_CAST (object); @@ -178,8 +182,7 @@ rtp_source_finalize (GObject * object) gst_buffer_unref (buffer); g_queue_free (src->packets); - for (i = 0; i < 9; i++) - g_free (src->sdes[i]); + gst_structure_free (src->sdes); g_free (src->bye_reason); @@ -281,88 +284,64 @@ rtp_source_create_stats (RTPSource * src) /** * rtp_source_get_sdes_struct: - * @src: an #RTSPSource + * @src: an #RTPSource * - * Get the SDES data as a GstStructure + * Get the SDES from @src. * - * Returns: a GstStructure with SDES items for @src. + * Returns: %GstStructure of type "application/x-rtp-source-sdes", see + * the SDES property for more details. */ GstStructure * rtp_source_get_sdes_struct (RTPSource * src) { - GstStructure *s; - gchar *str; + g_return_val_if_fail (RTP_IS_SOURCE (src), NULL); - s = gst_structure_new ("application/x-rtp-source-sdes", - "ssrc", G_TYPE_UINT, (guint) src->ssrc, NULL); + return gst_structure_copy (src->sdes); +} - if ((str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_CNAME))) { - gst_structure_set (s, "cname", G_TYPE_STRING, str, NULL); - g_free (str); - } - if ((str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_NAME))) { - gst_structure_set (s, "name", G_TYPE_STRING, str, NULL); - g_free (str); - } - if ((str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_EMAIL))) { - gst_structure_set (s, "email", G_TYPE_STRING, str, NULL); - g_free (str); - } - if ((str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_PHONE))) { - gst_structure_set (s, "phone", G_TYPE_STRING, str, NULL); - g_free (str); - } - if ((str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_LOC))) { - gst_structure_set (s, "location", G_TYPE_STRING, str, NULL); - g_free (str); - } - if ((str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_TOOL))) { - gst_structure_set (s, "tool", G_TYPE_STRING, str, NULL); - g_free (str); - } - if ((str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_NOTE))) { - gst_structure_set (s, "note", G_TYPE_STRING, str, NULL); - g_free (str); - } - return s; +static gboolean +sdes_struct_compare_func (GQuark field_id, const GValue * value, + gpointer user_data) +{ + GstStructure *old = GST_STRUCTURE (user_data); + const gchar *field = g_quark_to_string (field_id); + + if (!gst_structure_has_field (old, field)) + return FALSE; + + g_assert (G_VALUE_HOLDS_STRING (value)); + return strcmp (g_value_get_string (value), gst_structure_get_string (old, + field)) == 0; } /** - * rtp_source_set_sdes_struct: - * @src: an #RTSPSource - * @sdes: a #GstStructure with SDES info + * rtp_source_set_sdes: + * @src: an #RTPSource + * @sdes: the SDES structure * - * Set the SDES items from @sdes. + * Store the @sdes in @src. @sdes must be a structure of type + * "application/x-rtp-source-sdes", see the SDES property for more details. + * + * Returns: %FALSE if the SDES was unchanged. */ -void +gboolean rtp_source_set_sdes_struct (RTPSource * src, const GstStructure * sdes) { - const gchar *str; + gboolean changed; - if (!gst_structure_has_name (sdes, "application/x-rtp-source-sdes")) - return; + g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE); - if ((str = gst_structure_get_string (sdes, "cname"))) { - rtp_source_set_sdes_string (src, GST_RTCP_SDES_CNAME, str); - } - if ((str = gst_structure_get_string (sdes, "name"))) { - rtp_source_set_sdes_string (src, GST_RTCP_SDES_NAME, str); - } - if ((str = gst_structure_get_string (sdes, "email"))) { - rtp_source_set_sdes_string (src, GST_RTCP_SDES_EMAIL, str); - } - if ((str = gst_structure_get_string (sdes, "phone"))) { - rtp_source_set_sdes_string (src, GST_RTCP_SDES_PHONE, str); - } - if ((str = gst_structure_get_string (sdes, "location"))) { - rtp_source_set_sdes_string (src, GST_RTCP_SDES_LOC, str); - } - if ((str = gst_structure_get_string (sdes, "tool"))) { - rtp_source_set_sdes_string (src, GST_RTCP_SDES_TOOL, str); - } - if ((str = gst_structure_get_string (sdes, "note"))) { - rtp_source_set_sdes_string (src, GST_RTCP_SDES_NOTE, str); + g_return_val_if_fail (strcmp (gst_structure_get_name (sdes), + "application/x-rtp-source-sdes") == 0, FALSE); + + changed = !gst_structure_foreach (sdes, sdes_struct_compare_func, src->sdes); + + if (changed) { + gst_structure_free (src->sdes); + src->sdes = gst_structure_copy (sdes); } + + return changed; } static void @@ -657,54 +636,12 @@ rtp_source_update_caps (RTPSource * src, GstCaps * caps) } /** - * rtp_source_set_sdes: - * @src: an #RTPSource - * @type: the type of the SDES item - * @data: the SDES data - * @len: the SDES length - * - * Store an SDES item of @type in @src. - * - * Returns: %FALSE if the SDES item was unchanged or @type is unknown. - */ -gboolean -rtp_source_set_sdes (RTPSource * src, GstRTCPSDESType type, - const guint8 * data, guint len) -{ - guint8 *old; - - g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE); - - if (type < 0 || type > GST_RTCP_SDES_PRIV) - return FALSE; - - old = src->sdes[type]; - - /* lengths are the same, check if the data is the same */ - if ((src->sdes_len[type] == len)) - if (data != NULL && old != NULL && (memcmp (old, data, len) == 0)) - return FALSE; - - /* NULL data, make sure we store 0 length or if no length is given, - * take strlen */ - if (data == NULL) - len = 0; - - g_free (src->sdes[type]); - src->sdes[type] = g_memdup (data, len); - src->sdes_len[type] = len; - - return TRUE; -} - -/** * rtp_source_set_sdes_string: * @src: an #RTPSource * @type: the type of the SDES item * @data: the SDES data * - * Store an SDES item of @type in @src. This function is similar to - * rtp_source_set_sdes() but takes a null-terminated string for convenience. + * Store an SDES item of @type in @src. * * Returns: %FALSE if the SDES item was unchanged or @type is unknown. */ @@ -712,48 +649,26 @@ gboolean rtp_source_set_sdes_string (RTPSource * src, GstRTCPSDESType type, const gchar * data) { - guint len; - gboolean result; + const gchar *old; + const gchar *field; - if (data) - len = strlen (data); - else - len = 0; - - result = rtp_source_set_sdes (src, type, (guint8 *) data, len); + field = gst_rtcp_sdes_type_to_name (type); - return result; -} + if (gst_structure_has_field (src->sdes, field)) + old = gst_structure_get_string (src->sdes, field); + else + old = NULL; -/** - * rtp_source_get_sdes: - * @src: an #RTPSource - * @type: the type of the SDES item - * @data: location to store the SDES data or NULL - * @len: location to store the SDES length or NULL - * - * Get the SDES item of @type from @src. Note that @data does not always point - * to a null-terminated string, use rtp_source_get_sdes_string() to retrieve a - * null-terminated string instead. - * - * @data remains valid until the next call to rtp_source_set_sdes(). - * - * Returns: %TRUE if @type was valid and @data and @len contain valid - * data. @data can be NULL when the item was unset. - */ -gboolean -rtp_source_get_sdes (RTPSource * src, GstRTCPSDESType type, guint8 ** data, - guint * len) -{ - g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE); + if (old == NULL && data == NULL) + return FALSE; - if (type < 0 || type > GST_RTCP_SDES_PRIV) + if (old != NULL && data != NULL && strcmp (old, data) == 0) return FALSE; - if (data) - *data = src->sdes[type]; - if (len) - *len = src->sdes_len[type]; + if (data == NULL) + gst_structure_remove_field (src->sdes, field); + else + gst_structure_set (src->sdes, field, G_TYPE_STRING, data, NULL); return TRUE; } @@ -772,13 +687,19 @@ gchar * rtp_source_get_sdes_string (RTPSource * src, GstRTCPSDESType type) { gchar *result; + const gchar *type_name; g_return_val_if_fail (RTP_IS_SOURCE (src), NULL); - if (type < 0 || type > GST_RTCP_SDES_PRIV) + if (type < 0 || type > GST_RTCP_SDES_PRIV - 1) + return NULL; + + type_name = gst_rtcp_sdes_type_to_name (type); + + if (!gst_structure_has_field (src->sdes, type_name)) return NULL; - result = g_strndup ((const gchar *) src->sdes[type], src->sdes_len[type]); + result = g_strdup (gst_structure_get_string (src->sdes, type_name)); return result; } diff --git a/gst/rtpmanager/rtpsource.h b/gst/rtpmanager/rtpsource.h index 8355bc0..5271d54 100644 --- a/gst/rtpmanager/rtpsource.h +++ b/gst/rtpmanager/rtpsource.h @@ -117,8 +117,7 @@ struct _RTPSource { gboolean is_csrc; gboolean is_sender; - guint8 *sdes[9]; - guint sdes_len[9]; + GstStructure *sdes; gboolean received_bye; gchar *bye_reason; @@ -179,16 +178,11 @@ gchar * rtp_source_get_bye_reason (RTPSource *src); void rtp_source_update_caps (RTPSource *src, GstCaps *caps); /* SDES info */ -gboolean rtp_source_set_sdes (RTPSource *src, GstRTCPSDESType type, - const guint8 *data, guint len); gboolean rtp_source_set_sdes_string (RTPSource *src, GstRTCPSDESType type, const gchar *data); -gboolean rtp_source_get_sdes (RTPSource *src, GstRTCPSDESType type, - guint8 **data, guint *len); gchar* rtp_source_get_sdes_string (RTPSource *src, GstRTCPSDESType type); - GstStructure * rtp_source_get_sdes_struct (RTPSource * src); -void rtp_source_set_sdes_struct (RTPSource * src, const GstStructure *sdes); +gboolean rtp_source_set_sdes_struct (RTPSource * src, const GstStructure *sdes); /* handling network address */ void rtp_source_set_rtp_from (RTPSource *src, GstNetAddress *address); -- 2.7.4