[farsight2/master] rtpspecificnego: Add handling of telephone-event event ranges
Olivier Crête
olivier.crete at collabora.co.uk
Sat Jan 2 14:47:09 PST 2010
---
gst/fsrtpconference/fs-rtp-specific-nego.c | 229 ++++++++++++++++++++++++++++
1 files changed, 229 insertions(+), 0 deletions(-)
diff --git a/gst/fsrtpconference/fs-rtp-specific-nego.c b/gst/fsrtpconference/fs-rtp-specific-nego.c
index c241d62..0900d24 100644
--- a/gst/fsrtpconference/fs-rtp-specific-nego.c
+++ b/gst/fsrtpconference/fs-rtp-specific-nego.c
@@ -64,6 +64,9 @@ sdp_is_compat_h263_2000 (FsCodec *local_codec, FsCodec *remote_codec,
static FsCodec *
sdp_is_compat_theora_vorbis (FsCodec *local_codec, FsCodec *remote_codec,
gboolean validate_config);
+static FsCodec *
+sdp_is_compat_telephone_event (FsCodec *local_codec, FsCodec *remote_codec,
+ gboolean validate_config);
static struct SdpCompatCheck sdp_compat_checks[] = {
{FS_MEDIA_TYPE_AUDIO, "iLBC", sdp_is_compat_ilbc,
@@ -77,6 +80,8 @@ static struct SdpCompatCheck sdp_compat_checks[] = {
{FS_MEDIA_TYPE_VIDEO, "H264", sdp_is_compat_default,
{"sprop-parameter-sets", "sprop-interleaving-depth", "sprop-deint-buf-req",
"sprop-init-buf-time", "sprop-max-don-diff", NULL}},
+ {FS_MEDIA_TYPE_AUDIO, "telephone-event", sdp_is_compat_telephone_event,
+ {NULL}},
{0, NULL, NULL}
};
@@ -397,3 +402,227 @@ gboolean validate_config)
return sdp_is_compat_default (local_codec, remote_codec, validate_config);
}
+
+struct event_range {
+ int first;
+ int last;
+};
+
+static gint
+event_range_cmp (gconstpointer a, gconstpointer b)
+{
+ const struct event_range *era = a;
+ const struct event_range *erb = b;
+
+ return era->first - erb->first;
+}
+
+static GList *
+parse_events (const gchar *events)
+{
+ gchar **ranges_strv;
+ GList *ranges = NULL;
+ int i;
+
+ ranges_strv = g_strsplit (events, ",", 0);
+
+ for (i = 0; ranges_strv[i]; i++)
+ {
+ struct event_range *er = g_slice_new (struct event_range);
+
+ er->first = atoi (ranges_strv[i]);
+ if (index (ranges_strv[i], '-'))
+ er->last = atoi (index (ranges_strv[i], '-') + 1);
+
+ ranges = g_list_insert_sorted (ranges, er, event_range_cmp);
+ }
+
+ g_strfreev (ranges_strv);
+
+ return ranges;
+}
+
+static void
+event_range_free (gpointer data)
+{
+ g_slice_free (struct event_range, data);
+}
+
+static gchar *
+event_intersection (const gchar *remote_events, const gchar *local_events)
+{
+ GList *remote_ranges = NULL;
+ GList *local_ranges = NULL;
+ GList *intersected_ranges = NULL;
+ GList *item;
+ struct event_range *new_er = NULL;
+ GString *intersection_gstr;
+
+ if (!g_regex_match_simple ("^[0-9]+(-[0-9]+)?(,[0-9]+(-[0-9]+)?)*$",
+ remote_events, 0, 0))
+ {
+ GST_DEBUG ("Invalid remote events (events=%s)", remote_events);
+ return NULL;
+ }
+
+ if (!g_regex_match_simple ("^[0-9]+(-[0-9]+)?(,[0-9]+(-[0-9]+)?)*$",
+ local_events, 0, 0))
+ {
+ GST_DEBUG ("Invalid local events (events=%s)", local_events);
+ return NULL;
+ }
+
+ remote_ranges = parse_events (remote_events);
+ local_ranges = parse_events (local_events);
+
+ while ((item = remote_ranges) != NULL)
+ {
+ struct event_range *er1 = item->data;
+ GList *item2;
+
+ while ((item2 = local_ranges) != NULL)
+ {
+ struct event_range *er2 = item2->data;
+
+ if (er1->last < er2->first)
+ break;
+
+ if (er1->first < er2->last)
+ {
+ int new_first = MAX (er1->first, er2->first);
+ int new_last = MIN (er1->last, er2->last);
+
+ if (new_er && new_er->last == new_first)
+ {
+ new_er->last = new_last;
+ }
+ else
+ {
+ new_er = g_slice_new (struct event_range);
+ new_er->first = new_first;
+ new_er->last = new_last;
+ intersected_ranges = g_list_append (intersected_ranges, new_er);
+ }
+ }
+ local_ranges = g_list_delete_link (local_ranges, item2);
+ event_range_free (er2);
+ }
+
+ remote_ranges = g_list_delete_link (remote_ranges, item);
+ event_range_free (er1);
+ }
+
+ if (!intersected_ranges)
+ {
+ GST_DEBUG ("There is no intersection before the events %s and %s",
+ remote_events, local_events);
+ return NULL;
+ }
+
+ intersection_gstr = g_string_new ("");
+
+ while ((item = intersected_ranges) != NULL)
+ {
+ struct event_range *er = item->data;
+
+ if (intersection_gstr->len)
+ g_string_append_c (intersection_gstr, ',');
+
+ if (er->first == er->last)
+ g_string_append_printf (intersection_gstr, "%d", er->first);
+ else
+ g_string_append_printf (intersection_gstr, "%d-%d", er->first, er->last);
+
+ intersected_ranges = g_list_delete_link (intersected_ranges, item);
+ event_range_free (er);
+ }
+
+ return g_string_free (intersection_gstr, FALSE);
+}
+
+static FsCodec *
+sdp_is_compat_telephone_event (FsCodec *local_codec, FsCodec *remote_codec,
+ gboolean validate_config)
+{
+ FsCodec *negotiated_codec = NULL;
+ GList *local_param_list = NULL, *negotiated_param_list = NULL;
+
+ GST_LOG ("Using telephone-event codec negotiation function");
+
+ if ((local_codec->clock_rate || validate_config) &&
+ remote_codec->clock_rate &&
+ local_codec->clock_rate != remote_codec->clock_rate)
+ {
+ GST_LOG ("Clock rates differ local=%u remote=%u", local_codec->clock_rate,
+ remote_codec->clock_rate);
+ return NULL;
+ }
+
+ negotiated_codec = codec_copy_without_config (remote_codec);
+
+ negotiated_codec->ABI.ABI.ptime = local_codec->ABI.ABI.ptime;
+ negotiated_codec->ABI.ABI.maxptime = local_codec->ABI.ABI.maxptime;
+
+ /* Lets fix here missing clock rates and channels counts */
+ if (negotiated_codec->channels == 0 && local_codec->channels)
+ negotiated_codec->channels = local_codec->channels;
+ if (negotiated_codec->clock_rate == 0)
+ negotiated_codec->clock_rate = local_codec->clock_rate;
+
+ for (local_param_list = local_codec->optional_params;
+ local_param_list;
+ local_param_list = g_list_next (local_param_list))
+ {
+ FsCodecParameter *local_param = local_param_list->data;
+
+ for (negotiated_param_list = negotiated_codec->optional_params;
+ negotiated_param_list;
+ negotiated_param_list = g_list_next (negotiated_param_list))
+ {
+ FsCodecParameter *negotiated_param = negotiated_param_list->data;
+
+ if (!strcmp (negotiated_param->name, ""))
+ {
+ g_free (negotiated_param->name);
+ negotiated_param->name = g_strdup ("events");
+ }
+
+ if (!g_ascii_strcasecmp (local_param->name, negotiated_param->name))
+ {
+ if (!strcmp (local_param->value, negotiated_param->value))
+ {
+ break;
+ }
+ else if (!g_ascii_strcasecmp (negotiated_param->name, "events"))
+ {
+ gchar *events = event_intersection (negotiated_param->value,
+ local_param->value);
+ if (!events)
+ {
+ GST_LOG ("Non-intersecting values for %s, local=%s remote=%s",
+ local_param->name, local_param->value, negotiated_param->value);
+ fs_codec_destroy (negotiated_codec);
+ return NULL;
+ }
+ g_free (negotiated_param->value);
+ negotiated_param->value = events;
+ }
+ else
+ {
+ GST_LOG ("Different values for %s, local=%s remote=%s",
+ local_param->name, local_param->value, negotiated_param->value);
+ fs_codec_destroy (negotiated_codec);
+ return NULL;
+ }
+ }
+ }
+
+ /* Let's add the local param to the negotiated codec if it does not exist in
+ * the remote codec */
+ if (!negotiated_param_list)
+ fs_codec_add_optional_parameter (negotiated_codec, local_param->name,
+ local_param->value);
+ }
+
+ return negotiated_codec;
+}
--
1.5.6.5
More information about the farsight-commits
mailing list