[farsight2/master] Import the local codec list generation code from Farsight 1
Olivier Crête
olivier.crete at collabora.co.uk
Tue Dec 23 15:19:51 PST 2008
---
gst/fsrtpconference/Makefile.am | 6 +-
gst/fsrtpconference/fs-rtp-codec-negotiation.c | 424 ++++++++++++++++++++++++
gst/fsrtpconference/fs-rtp-codec-negotiation.h | 60 ++++
3 files changed, 488 insertions(+), 2 deletions(-)
create mode 100644 gst/fsrtpconference/fs-rtp-codec-negotiation.c
create mode 100644 gst/fsrtpconference/fs-rtp-codec-negotiation.h
diff --git a/gst/fsrtpconference/Makefile.am b/gst/fsrtpconference/Makefile.am
index 3e00dab..998285c 100644
--- a/gst/fsrtpconference/Makefile.am
+++ b/gst/fsrtpconference/Makefile.am
@@ -6,7 +6,8 @@ libfsrtpconference_la_SOURCES = gstfsrtpconference.c \
fs-rtp-session.c \
fs-rtp-stream.c \
fs-rtp-discover-codecs.c \
- fs-rtp-codec-cache.c
+ fs-rtp-codec-cache.c \
+ fs-rtp-codec-negotiation.c
libfsrtpconference_la_CFLAGS = $(FS2_INTERNAL_CFLAGS) $(FS2_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
libfsrtpconference_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libfsrtpconference_la_LIBADD = \
@@ -20,4 +21,5 @@ noinst_HEADERS = \
fs-rtp-session.h \
fs-rtp-stream.h \
fs-rtp-discover-codecs.h \
- fs-rtp-codec-cache.h
+ fs-rtp-codec-cache.h \
+ fs-rtp-codec-negotiation.h
diff --git a/gst/fsrtpconference/fs-rtp-codec-negotiation.c b/gst/fsrtpconference/fs-rtp-codec-negotiation.c
new file mode 100644
index 0000000..b4a5c05
--- /dev/null
+++ b/gst/fsrtpconference/fs-rtp-codec-negotiation.c
@@ -0,0 +1,424 @@
+/*
+ * Farsight2 - Farsight RTP Codec Negotiation
+ *
+ * Copyright 2007 Collabora Ltd.
+ * @author: Olivier Crete <olivier.crete at collabora.co.uk>
+ * Copyright 2007 Nokia Corp.
+ *
+ * fs-discover-codecs.h - A Farsight RTP Codec Negotiation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "fs-rtp-codec-negotiation.h"
+
+
+/**
+ * validate_codecs_configuration:
+ * @media_type: The #FsMediaType these codecs should be for
+ * @blueprints: A #GList of #CodecBlueprints to validate the codecs agsint
+ * @codecs: a #GList of #FsCodec that represent the preferences
+ *
+ * This function validates a GList of passed FarsightCodec structures
+ * against the valid discovered payloaders
+ * It removes all "invalid" codecs from the list
+ *
+ * Returns: a #GList of #FsCodec minus the invalid ones
+ */
+GList *
+validate_codecs_configuration (FsMediaType media_type, GList *blueprints,
+ GList *codecs)
+{
+ GList *codec_e = codecs;
+
+ while (codec_e) {
+ FsCodec *codec = codec_e->data;
+ GList *blueprint_e = NULL;
+
+ /* Check if codec is for the wrong media_type.. this would be wrong
+ */
+ if (media_type != codec->media_type) {
+ goto remove_this_codec;
+ }
+
+ for (blueprint_e = g_list_first (blueprints);
+ blueprint_e;
+ blueprint_e = g_list_next (blueprint_e)) {
+ CodecBlueprint *blueprint = blueprint_e->data;
+ GList *codecparam_e = NULL;
+
+ /* First, lets check the encoding name */
+ if (g_ascii_strcasecmp (blueprint->codec->encoding_name,
+ codec->encoding_name))
+ continue;
+ /* If both have a clock_rate, it must be the same */
+ if (blueprint->codec->clock_rate && codec->clock_rate &&
+ blueprint->codec->clock_rate != codec->clock_rate) {
+ continue;
+ /* At least one needs to have a clockrate */
+ } else if (!blueprint->codec->clock_rate && !codec->clock_rate) {
+ continue;
+ }
+
+ /* Now lets check that all params that are present in both
+ * match
+ */
+ for (codecparam_e = codec->optional_params;
+ codecparam_e;
+ codecparam_e = g_list_next (codecparam_e)) {
+ FsCodecParameter *codecparam = codecparam_e->data;
+ GList *bpparam_e = NULL;
+ for (bpparam_e = blueprint->codec->optional_params;
+ bpparam_e;
+ bpparam_e = g_list_next (bpparam_e)) {
+ FsCodecParameter *bpparam = bpparam_e->data;
+ if (!g_ascii_strcasecmp (codecparam->name, bpparam->name)) {
+ /* If the blueprint and the codec specify the value
+ * of a parameter, they should be the same
+ */
+ if (g_ascii_strcasecmp (codecparam->value, bpparam->value)) {
+ goto next_blueprint;
+ }
+ break;
+ }
+ }
+ }
+ break;
+ next_blueprint:
+ continue;
+ }
+
+ /* If no blueprint was found */
+ if (blueprint_e == NULL) {
+ goto remove_this_codec;
+ }
+
+ codec_e = g_list_next (codec_e);
+
+ continue;
+ remove_this_codec:
+ {
+ GList *nextcodec_e = g_list_next (codec_e);
+ gchar *tmp = fs_codec_to_string (codec);
+ g_debug ("Prefered codec %s could not be matched with a blueprint", tmp);
+ g_free (tmp);
+ fs_codec_destroy (codec);
+ codecs = g_list_delete_link (codecs, codec_e);
+ codec_e = nextcodec_e;
+ }
+ }
+
+ return codecs;
+}
+
+
+static void
+_codec_association_destroy (CodecAssociation *ca)
+{
+ if (!ca)
+ return;
+
+ fs_codec_destroy (ca->codec);
+ g_free (ca);
+}
+
+
+static CodecBlueprint *
+_find_matching_blueprint (FsCodec *codec, GList *blueprints)
+{
+ GList *item = NULL;
+ GstCaps *caps = NULL;
+
+ if (item == NULL)
+ return NULL;
+
+ caps = fs_codec_to_gst_caps (codec);
+
+ if (!caps)
+ return NULL;
+
+ for (item = g_list_first (blueprints); item; item = g_list_next (item)) {
+ CodecBlueprint *bp = item->data;
+ GstCaps *intersectedcaps = NULL;
+ gboolean ok = FALSE;
+
+ intersectedcaps = gst_caps_intersect (caps, bp->rtp_caps);
+
+ if (!gst_caps_is_empty (intersectedcaps))
+ ok = TRUE;
+
+ gst_caps_unref (intersectedcaps);
+
+ if (ok)
+ break;
+ }
+
+ gst_caps_unref (caps);
+
+ if (item)
+ return item->data;
+ else
+ return NULL;
+}
+
+static gint
+_find_first_empty_dynamic_entry (GHashTable *new_codec_associations,
+ GHashTable *old_codec_associations)
+{
+ int id;
+
+ for (id = 96; id < 128; id++) {
+ if (new_codec_associations &&
+ g_hash_table_lookup_extended (new_codec_associations,
+ GINT_TO_POINTER (id), NULL, NULL))
+ continue;
+ if (old_codec_associations &&
+ g_hash_table_lookup_extended (old_codec_associations,
+ GINT_TO_POINTER (id), NULL, NULL))
+ continue;
+ return id;
+ }
+
+ return -1;
+}
+
+static gboolean
+_ht_has_codec_blueprint (gpointer key, gpointer value, gpointer user_data)
+{
+ CodecAssociation *ca = value;
+
+ if (ca->blueprint == user_data)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static gboolean
+_is_disabled (GList *codec_prefs, CodecBlueprint *bp)
+{
+ GList *item = NULL;
+
+ for (item = g_list_first (codec_prefs); item; item = g_list_next (item)) {
+ FsCodec *codec = item->data;
+ GstCaps *intersectedcaps = NULL;
+ GstCaps *caps = NULL;
+ gboolean ok = FALSE;
+
+ /* Only check for DISABLE entries */
+ if (codec->id != FS_CODEC_ID_DISABLE)
+ continue;
+
+ caps = fs_codec_to_gst_caps (codec);
+ if (!caps)
+ continue;
+
+ intersectedcaps = gst_caps_intersect (caps, bp->rtp_caps);
+
+ if (!gst_caps_is_empty (intersectedcaps))
+ ok = TRUE;
+
+ gst_caps_unref (intersectedcaps);
+ gst_caps_unref (caps);
+
+ if (ok)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+GHashTable *create_local_codec_associations (FsMediaType media_type,
+ GList *blueprints, GList *codec_prefs, GHashTable *current_codec_associations,
+ GList **local_codecs_list)
+{
+ GHashTable *codec_associations = NULL;
+ GList *bp_e = NULL;
+ GList *local_codecs = NULL;
+ GList *local_codec_association_list = NULL;
+ GList *codec_pref_e = NULL;
+ GList *lca_e = NULL;
+
+ *local_codecs_list = NULL;
+
+ if (blueprints == NULL)
+ return NULL;
+
+ codec_associations = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) _codec_association_destroy);
+
+ /* First, lets create the original table by looking at our prefered codecs */
+ for (codec_pref_e = codec_prefs;
+ codec_pref_e;
+ codec_pref_e = g_list_next (codec_pref_e)) {
+ FsCodec *codec_pref = codec_pref_e->data;
+ CodecBlueprint *bp = _find_matching_blueprint (codec_pref, blueprints);
+ CodecAssociation *ca = NULL;
+ GList *bp_param_e = NULL;
+
+ /* No matching blueprint, can't use this codec */
+ if (!bp)
+ continue;
+
+ /* If its a negative pref, ignore it in this stage */
+ if (codec_pref->id == FS_CODEC_ID_DISABLE)
+ continue;
+
+ ca = g_new0 (CodecAssociation, 1);
+ ca->blueprint = bp;
+ ca->codec = fs_codec_copy (codec_pref);
+
+ /* Codec pref does not come with a number, but
+ * The blueprint has its own id, lets use it */
+ if (ca->codec->id == FS_CODEC_ID_ANY &&
+ (bp->codec->id >= 0 || bp->codec->id < 128)) {
+ ca->codec->id = bp->codec->id;
+ }
+
+ if (ca->codec->clock_rate <= 0) {
+ ca->codec->clock_rate = bp->codec->clock_rate;
+ }
+
+ if (ca->codec->channels == 0) {
+ ca->codec->channels = bp->codec->channels;
+ }
+
+ for (bp_param_e = bp->codec->optional_params;
+ bp_param_e;
+ bp_param_e = g_list_next (bp_param_e)) {
+ GList *pref_param_e = NULL;
+ FsCodecParameter *bp_param = bp_param_e->data;
+ for (pref_param_e = ca->codec->optional_params;
+ pref_param_e;
+ pref_param_e = g_list_next (pref_param_e)) {
+ FsCodecParameter *pref_param = pref_param_e->data;
+ if (!g_ascii_strcasecmp (bp_param->name, pref_param->name))
+ break;
+ }
+ if (!pref_param_e) {
+ FsCodecParameter *newparam = g_new0 (FsCodecParameter, 1);
+ newparam->name = g_strdup (bp_param->name);
+ newparam->value = g_strdup (bp_param->value);
+ ca->codec->optional_params = g_list_append (ca->codec->optional_params,
+ newparam);
+ }
+ }
+
+ local_codec_association_list = g_list_append (local_codec_association_list,
+ ca);
+ }
+
+ /* Now, only codecs with specified ids are here,
+ * the rest are dynamic
+ * Lets attribute them here */
+ lca_e = local_codec_association_list;
+ while (lca_e) {
+ CodecAssociation *lca = lca_e->data;
+ GList *next = g_list_next (lca_e);
+
+ if (g_hash_table_lookup_extended (codec_associations,
+ GINT_TO_POINTER (lca->codec->id), NULL, NULL) ||
+ lca->codec->id < 0) {
+ lca->codec->id = _find_first_empty_dynamic_entry (
+ current_codec_associations, codec_associations);
+ if (lca->codec->id < 0) {
+ g_warning ("We've run out of dynamic payload types");
+ goto out;
+ }
+ }
+
+ local_codecs = g_list_append (local_codecs, lca->codec);
+ g_hash_table_insert (codec_associations, GINT_TO_POINTER (lca->codec->id),
+ lca);
+
+ local_codec_association_list = g_list_delete_link (
+ local_codec_association_list, lca_e);
+ lca_e = next;
+ }
+
+ /* Now, lets add all other codecs from the blueprints */
+ for (bp_e = g_list_first (blueprints); bp_e; bp_e = g_list_next (bp_e)) {
+ CodecBlueprint *bp = bp_e->data;
+ CodecAssociation *ca = NULL;
+
+ /* Lets skip codecs that dont have all of the required informations */
+ if (bp->codec->clock_rate <= 0) {
+ continue;
+ }
+
+ /* Check if its already used */
+ if (g_hash_table_find (codec_associations, _ht_has_codec_blueprint, bp))
+ continue;
+
+ /* Check if it is disabled in the list of prefered codecs */
+ if (_is_disabled (codec_prefs, bp)) {
+ gchar *tmp = fs_codec_to_string (bp->codec);
+ g_debug ("Codec %s disabled by config", tmp);
+ g_free (tmp);
+ continue;
+ }
+
+ ca = g_new0 (CodecAssociation, 1);
+ ca->blueprint = bp;
+ ca->codec = fs_codec_copy (bp->codec);
+
+ if (ca->codec->id < 0) {
+ ca->codec->id = _find_first_empty_dynamic_entry (
+ current_codec_associations, codec_associations);
+ if (ca->codec->id < 0) {
+ g_warning ("We've run out of dynamic payload types");
+ goto out;
+ }
+ }
+
+ g_hash_table_insert (codec_associations, GINT_TO_POINTER (ca->codec->id),
+ ca);
+ local_codecs = g_list_append (local_codecs, ca->codec);
+ }
+
+ out:
+
+ g_list_foreach (local_codec_association_list,
+ (GFunc) _codec_association_destroy,
+ NULL);
+ g_list_free (local_codec_association_list);
+
+#if 0
+ /*
+ * BIG hack, we have to manually add CN
+ * because we can send it, but not receive it yet
+ * Do the same for DTMF for the same reason
+ * This is because there is no blueprint for them
+ */
+ if (media_type == FS_MEDIA_TYPE_AUDIO && local_codecs) {
+ local_codecs = _add_cn_type (local_codecs, codec_associations);
+ local_codecs = _add_dtmf_type (local_codecs, codec_associations,
+ current_codec_associations, NULL);
+ }
+#endif
+
+ *local_codecs_list = local_codecs;
+
+ /* If no local codecs where detected */
+ if (!local_codecs) {
+ g_hash_table_destroy (codec_associations);
+ codec_associations = NULL;
+ g_debug ("There are no local codecs for this stream of media type %s",
+ fs_media_type_to_string (media_type));
+ }
+
+ return codec_associations;
+}
+
diff --git a/gst/fsrtpconference/fs-rtp-codec-negotiation.h b/gst/fsrtpconference/fs-rtp-codec-negotiation.h
new file mode 100644
index 0000000..1f6fd8f
--- /dev/null
+++ b/gst/fsrtpconference/fs-rtp-codec-negotiation.h
@@ -0,0 +1,60 @@
+/*
+ * Farsight2 - Farsight RTP Codec Negotiation
+ *
+ * Copyright 2007 Collabora Ltd.
+ * @author: Olivier Crete <olivier.crete at collabora.co.uk>
+ * Copyright 2007 Nokia Corp.
+ *
+ * fs-discover-codecs.h - A Farsight RTP Codec Negotiation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __FS_RTP_CODEC_NEGOTIATION_H__
+#define __FS_RTP_CODEC_NEGOTIATION_H__
+
+#include "fs-rtp-discover-codecs.h"
+
+G_BEGIN_DECLS
+
+typedef struct _CodecAssociation {
+ CodecBlueprint *blueprint;
+ FsCodec *codec;
+} CodecAssociation;
+
+
+GList *validate_codecs_configuration (FsMediaType media_type, GList *blueprints,
+ GList *codecs);
+
+GHashTable *create_local_codec_associations (FsMediaType media_type,
+ GList *blueprints, GList *codec_prefs, GHashTable *current_codec_associations,
+ GList **local_codecs_list);
+
+#if 0
+
+GHashTable *negotiate_codecs (const GList *remote_codecs,
+ GHashTable *current_negotiated_codec_associations,
+ GHashTable *local_codec_associations, GList *local_codecs,
+ GList **new_negotiated_codecs);
+
+CodecAssociation *lookup_codec_association_by_pt (
+ GHashTable *codec_associations, gint pt);
+
+#endif
+
+
+G_END_DECLS
+
+#endif /* __FS_RTP_CODEC_NEGOTIATION_H__ */
--
1.5.6.5
More information about the farsight-commits
mailing list