[farsight2/master] Import for the codec negotiation code from Farsight 1
Olivier Crête
olivier.crete at collabora.co.uk
Tue Dec 23 15:19:52 PST 2008
---
gst/fsrtpconference/Makefile.am | 6 +-
gst/fsrtpconference/fs-rtp-codec-negotiation.c | 196 +++++++++++++
gst/fsrtpconference/fs-rtp-codec-negotiation.h | 3 -
gst/fsrtpconference/fs-rtp-specific-nego.c | 347 ++++++++++++++++++++++++
gst/fsrtpconference/fs-rtp-specific-nego.h | 40 +++
5 files changed, 587 insertions(+), 5 deletions(-)
create mode 100644 gst/fsrtpconference/fs-rtp-specific-nego.c
create mode 100644 gst/fsrtpconference/fs-rtp-specific-nego.h
diff --git a/gst/fsrtpconference/Makefile.am b/gst/fsrtpconference/Makefile.am
index 998285c..9c7da5d 100644
--- a/gst/fsrtpconference/Makefile.am
+++ b/gst/fsrtpconference/Makefile.am
@@ -7,7 +7,8 @@ libfsrtpconference_la_SOURCES = gstfsrtpconference.c \
fs-rtp-stream.c \
fs-rtp-discover-codecs.c \
fs-rtp-codec-cache.c \
- fs-rtp-codec-negotiation.c
+ fs-rtp-codec-negotiation.c \
+ fs-rtp-specific-nego.c
libfsrtpconference_la_CFLAGS = $(FS2_INTERNAL_CFLAGS) $(FS2_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
libfsrtpconference_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libfsrtpconference_la_LIBADD = \
@@ -22,4 +23,5 @@ noinst_HEADERS = \
fs-rtp-stream.h \
fs-rtp-discover-codecs.h \
fs-rtp-codec-cache.h \
- fs-rtp-codec-negotiation.h
+ fs-rtp-codec-negotiation.h \
+ fs-rtp-specific-nego.h
diff --git a/gst/fsrtpconference/fs-rtp-codec-negotiation.c b/gst/fsrtpconference/fs-rtp-codec-negotiation.c
index b4a5c05..a04b7f1 100644
--- a/gst/fsrtpconference/fs-rtp-codec-negotiation.c
+++ b/gst/fsrtpconference/fs-rtp-codec-negotiation.c
@@ -24,6 +24,7 @@
#include "fs-rtp-codec-negotiation.h"
+#include "fs-rtp-specific-nego.h"
/**
* validate_codecs_configuration:
@@ -422,3 +423,198 @@ GHashTable *create_local_codec_associations (FsMediaType media_type,
return codec_associations;
}
+
+
+
+
+struct SDPNegoData {
+ /* in */
+ FsCodec *remote_codec;
+ /* out */
+ CodecAssociation *local_ca;
+ FsCodec *nego_codec;
+};
+
+
+static gboolean
+_do_sdp_codec_nego (gpointer key, gpointer value, gpointer user_data)
+{
+ struct SDPNegoData *tmpdata = user_data;
+ CodecAssociation *local_ca = value;
+ FsCodec *nego_codec = NULL;
+
+ if (local_ca == NULL)
+ return FALSE;
+
+ nego_codec = sdp_is_compat (local_ca->blueprint->rtp_caps,
+ local_ca->codec, tmpdata->remote_codec);
+
+ if (nego_codec) {
+ tmpdata->nego_codec = nego_codec;
+ tmpdata->local_ca = local_ca;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+GHashTable *
+negotiate_codecs (const GList *remote_codecs,
+ GHashTable *negotiated_codec_associations,
+ GHashTable *local_codec_associations, GList *local_codecs,
+ GList **negotiated_codecs_out)
+{
+ GHashTable *new_codec_associations = NULL;
+ GList *new_negotiated_codecs = NULL;
+ const GList *rcodec_e = NULL;
+ int i;
+
+ g_return_val_if_fail (remote_codecs, NULL);
+ g_return_val_if_fail (local_codec_associations, NULL);
+ g_return_val_if_fail (local_codecs, NULL);
+
+ new_codec_associations = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal, NULL, (GDestroyNotify) _codec_association_destroy);
+
+ for (rcodec_e = remote_codecs;
+ rcodec_e;
+ rcodec_e = g_list_next (rcodec_e)) {
+ FsCodec *remote_codec = rcodec_e->data;
+ FsCodec *nego_codec = NULL;
+ CodecAssociation *local_ca = NULL;
+
+ gchar *tmp = fs_codec_to_string (remote_codec);
+ g_debug ("Remote codec %s", tmp);
+ g_free (tmp);
+
+ /* First lets try the codec that is in the same PT */
+
+ local_ca = lookup_codec_association_by_pt (local_codec_associations,
+ remote_codec->id);
+
+ if (local_ca) {
+ g_debug ("Have local codec in the same PT, lets try it first");
+ nego_codec = sdp_is_compat (local_ca->blueprint->rtp_caps,
+ local_ca->codec, remote_codec);
+ }
+
+ if (!nego_codec) {
+ struct SDPNegoData tmpdata;
+ tmpdata.remote_codec = remote_codec;
+ tmpdata.local_ca = NULL;
+ tmpdata.nego_codec = NULL;
+
+ g_hash_table_find (local_codec_associations, _do_sdp_codec_nego,
+ &tmpdata);
+
+ if (tmpdata.local_ca && tmpdata.nego_codec) {
+ local_ca = tmpdata.local_ca;
+ nego_codec = tmpdata.nego_codec;
+ }
+ }
+
+ if (nego_codec) {
+ CodecAssociation *new_ca = g_new0 (CodecAssociation, 1);
+ gchar *tmp;
+
+ new_ca->codec = fs_codec_copy (nego_codec);
+ new_ca->blueprint = local_ca->blueprint;
+ tmp = fs_codec_to_string (nego_codec);
+ g_debug ("Negotiated codec %s", tmp);
+ g_free (tmp);
+
+ g_hash_table_insert (new_codec_associations,
+ GINT_TO_POINTER (remote_codec->id), new_ca);
+ new_negotiated_codecs = g_list_append (new_negotiated_codecs, new_ca->codec);
+ } else {
+ gchar *tmp = fs_codec_to_string (remote_codec);
+ g_debug ("Could not find a valid intersection... for codec %s",
+ tmp);
+ g_free (tmp);
+ g_hash_table_insert (new_codec_associations,
+ GINT_TO_POINTER (remote_codec->id), NULL);
+ }
+ }
+
+ /* If no intersection was found, lets return NULL */
+ if (g_hash_table_size (new_codec_associations) == 0) {
+ g_hash_table_destroy (new_codec_associations);
+ return NULL;
+ }
+
+ /* Now, lets fill all of the PTs that were previously used in the session
+ * even if they are not currently used, so they can't be re-used
+ */
+ for (i=0; i < 128; i++) {
+ CodecAssociation *local_ca = NULL;
+
+ /* We can skip those currently in use */
+ if (g_hash_table_lookup_extended (new_codec_associations,
+ GINT_TO_POINTER (i), NULL, NULL))
+ continue;
+
+ /* We check if our local table (our offer) and if we offered
+ something, we add it. Some broken implementation (like Tandberg's)
+ send packets on PTs that they did not put in their response
+ */
+ local_ca = lookup_codec_association_by_pt (local_codec_associations, i);
+ if (local_ca) {
+ CodecAssociation *new_ca = g_new0 (CodecAssociation, 1);
+ new_ca->codec = fs_codec_copy (local_ca->codec);
+ new_ca->blueprint = local_ca->blueprint;
+
+ g_hash_table_insert (new_codec_associations,
+ GINT_TO_POINTER (i), new_ca);
+ /*
+ * We dont insert it into the list, because the list is used for offers
+ * and answers.. and we shouldn't offer/answer with codecs that
+ * were not in the remote codecs
+ */
+ //new_negotiated_codecs = g_list_append (new_negotiated_codecs, new_ca->codec);
+ continue;
+ }
+
+ /* We check in our local table (our offer) and in the old negotiated
+ * table (the result of previous negotiations). And kill all of the
+ * PTs used in there
+ */
+ if (g_hash_table_lookup_extended (local_codec_associations,
+ GINT_TO_POINTER (i), NULL, NULL)
+ || (negotiated_codec_associations &&
+ g_hash_table_lookup_extended (negotiated_codec_associations,
+ GINT_TO_POINTER (i), NULL, NULL))) {
+ g_hash_table_insert (new_codec_associations,
+ GINT_TO_POINTER (i), NULL);
+ }
+
+ }
+
+#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 (new_negotiated_codecs) {
+ new_negotiated_codecs = add_cn_type (new_negotiated_codecs,
+ new_codec_associations);
+ new_negotiated_codecs = add_dtmf_type (new_negotiated_codecs,
+ local_codec_associations, negotiated_codec_associations, remote_codecs);
+ }
+#endif
+
+ *negotiated_codecs_out = new_negotiated_codecs;
+ return new_codec_associations;
+}
+
+
+CodecAssociation *
+lookup_codec_association_by_pt (GHashTable *codec_associations, gint pt)
+{
+ if (!codec_associations)
+ return NULL;
+
+ return g_hash_table_lookup (codec_associations, GINT_TO_POINTER (pt));
+}
diff --git a/gst/fsrtpconference/fs-rtp-codec-negotiation.h b/gst/fsrtpconference/fs-rtp-codec-negotiation.h
index 1f6fd8f..4da310a 100644
--- a/gst/fsrtpconference/fs-rtp-codec-negotiation.h
+++ b/gst/fsrtpconference/fs-rtp-codec-negotiation.h
@@ -42,8 +42,6 @@ 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,
@@ -52,7 +50,6 @@ GHashTable *negotiate_codecs (const GList *remote_codecs,
CodecAssociation *lookup_codec_association_by_pt (
GHashTable *codec_associations, gint pt);
-#endif
G_END_DECLS
diff --git a/gst/fsrtpconference/fs-rtp-specific-nego.c b/gst/fsrtpconference/fs-rtp-specific-nego.c
new file mode 100644
index 0000000..d871e8f
--- /dev/null
+++ b/gst/fsrtpconference/fs-rtp-specific-nego.c
@@ -0,0 +1,347 @@
+/*
+ * fs-rtp-specific-nego.c - Per-codec SDP negociation
+ *
+ * Farsight RTP/AVP/SAVP/AVPF Module
+ * Copyright (C) 2007 Collabora Ltd.
+ * Copyright (C) 2007 Nokia Corporation
+ * @author Olivier Crete <olivier.crete at collabora.co.uk>
+ *
+ * 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 <string.h>
+
+#include <glib.h>
+#include <gst/gst.h>
+
+#include "fs-rtp-specific-nego.h"
+
+struct SdpCompatCheck {
+ FsMediaType media_type;
+ const gchar *encoding_name;
+ FsCodec * (* sdp_is_compat) (GstCaps *rtp_caps, FsCodec *local_codec,
+ FsCodec *remote_codec);
+};
+
+
+static FsCodec *
+sdp_is_compat_ilbc (GstCaps *rtp_caps, FsCodec *local_codec,
+ FsCodec *remote_codec);
+static FsCodec *
+sdp_is_compat_h263_1998 (GstCaps *rtp_caps, FsCodec *local_codec,
+ FsCodec *remote_codec);
+
+struct SdpCompatCheck sdp_compat_checks[] = {
+ {FS_MEDIA_TYPE_AUDIO, "iLBC", sdp_is_compat_ilbc},
+ {FS_MEDIA_TYPE_VIDEO, "H263-1998", sdp_is_compat_h263_1998},
+ {0, NULL, NULL}
+};
+
+
+static FsCodec *
+sdp_is_compat_default (GstCaps *rtp_caps, FsCodec *local_codec,
+ FsCodec *remote_codec);
+
+FsCodec *
+sdp_is_compat (GstCaps *rtp_caps, FsCodec *local_codec,
+ FsCodec *remote_codec)
+{
+ gint i;
+
+ g_assert (local_codec);
+ g_assert (remote_codec);
+ g_assert (rtp_caps);
+
+ if (local_codec->media_type != remote_codec->media_type) {
+ g_debug ("Wrong media type, local: %s, remote: %s",
+ fs_media_type_to_string (local_codec->media_type),
+ fs_media_type_to_string (remote_codec->media_type));
+ return NULL;
+ }
+ if (g_ascii_strcasecmp (local_codec->encoding_name,
+ remote_codec->encoding_name)) {
+ g_debug ("Encoding names dont match, local: %s, remote: %s",
+ local_codec->encoding_name, remote_codec->encoding_name);
+ return NULL;
+ }
+
+ for (i = 0; sdp_compat_checks[i].sdp_is_compat; i++) {
+ if (sdp_compat_checks[i].media_type == remote_codec->media_type &&
+ !g_ascii_strcasecmp (sdp_compat_checks[i].encoding_name,
+ remote_codec->encoding_name)) {
+ return sdp_compat_checks[i].sdp_is_compat (rtp_caps, local_codec,
+ remote_codec);
+ }
+ }
+
+ return sdp_is_compat_default (rtp_caps, local_codec, remote_codec);
+}
+
+static FsCodec *
+sdp_is_compat_default (GstCaps *rtp_caps, FsCodec *local_codec,
+ FsCodec *remote_codec)
+{
+ FsCodec *negotiated_codec = NULL;
+ GList *local_param_list = NULL, *negotiated_param_list = NULL;
+
+ g_debug ("Using default codec negotiation function");
+
+ if (remote_codec->clock_rate &&
+ local_codec->clock_rate != remote_codec->clock_rate) {
+ g_debug ("Clock rates differ local=%u remote=%u", local_codec->clock_rate,
+ remote_codec->clock_rate);
+ return NULL;
+ }
+
+ if (local_codec->channels && remote_codec->channels &&
+ local_codec->channels != remote_codec->channels) {
+ g_debug ("Channel counts differ local=%u remote=%u", local_codec->channels,
+ remote_codec->channels);
+ return NULL;
+ }
+
+ negotiated_codec = fs_codec_copy (remote_codec);
+
+ /* 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 (!g_ascii_strcasecmp (local_param->name, negotiated_param->name)) {
+ if (!strcmp (local_param->value, negotiated_param->value)) {
+ break;
+ } else {
+ g_debug ("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) {
+ FsCodecParameter *newparam = g_new (FsCodecParameter, 1);
+ newparam->name = g_strdup (local_param->name);
+ newparam->value = g_strdup (local_param->value);
+ negotiated_codec->optional_params = g_list_append (
+ negotiated_codec->optional_params, newparam);
+ }
+ }
+
+ return negotiated_codec;
+}
+
+static FsCodec *
+sdp_is_compat_ilbc (GstCaps *rtp_caps, FsCodec *local_codec,
+ FsCodec *remote_codec)
+{
+ FsCodec *negotiated_codec = NULL;
+ GList *mylistitem = NULL, *negotiated_param_list = NULL;
+ gboolean has_mode = FALSE;
+
+ g_debug ("Using ilbc negotiation function");
+
+ if (remote_codec->clock_rate &&
+ local_codec->clock_rate != remote_codec->clock_rate) {
+ g_debug ("Clock rates differ local=%u remote=%u", local_codec->clock_rate,
+ remote_codec->clock_rate);
+ return NULL;
+ }
+
+ if (local_codec->channels && remote_codec->channels &&
+ local_codec->channels != remote_codec->channels) {
+ g_debug ("Channel counts differ local=%u remote=%u", local_codec->channels,
+ remote_codec->channels);
+ return NULL;
+ }
+
+ negotiated_codec = fs_codec_copy (remote_codec);
+
+ /* 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 (mylistitem = local_codec->optional_params;
+ mylistitem;
+ mylistitem = g_list_next (mylistitem)) {
+ FsCodecParameter *local_param = mylistitem->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 (!g_ascii_strcasecmp (local_param->name, negotiated_param->name)) {
+ if (!g_ascii_strcasecmp (local_param->name, "mode")) {
+ gint local_mode = atoi (local_param->value);
+ gint remote_mode = atoi (negotiated_param->value);
+
+ has_mode = TRUE;
+
+ if (remote_mode != 20 && remote_mode != 30) {
+ g_debug ("Invalid mode on ilbc");
+ goto failure;
+ }
+ if (local_mode != remote_mode) {
+ g_free (negotiated_param->value);
+ negotiated_param->value = g_strdup ("30");
+ break;
+ }
+ } else {
+ if (!strcmp (local_param->value, negotiated_param->value)) {
+ break;
+ } else {
+ g_debug ("Different values for %s, local=%s remote=%s",
+ local_param->name, local_param->value, negotiated_param->value);
+ goto failure;
+ }
+ }
+ }
+ }
+
+ /* Let's add the local param to the negotiated codec if it does not exist in
+ * the remote codec */
+ if (!negotiated_param_list) {
+ FsCodecParameter *newparam = g_new (FsCodecParameter, 1);
+ newparam->name = g_strdup (local_param->name);
+ newparam->value = g_strdup (local_param->value);
+ negotiated_codec->optional_params = g_list_append (
+ negotiated_codec->optional_params, newparam);
+
+ if (!g_ascii_strcasecmp (local_param->name, "mode")) {
+ has_mode = TRUE;
+ }
+ }
+ }
+
+ /* If more has not be found in the local codec, let's check if it's in the
+ * remote codec */
+ if (!has_mode) {
+ 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 (!g_ascii_strcasecmp (negotiated_param->name, "mode")) {
+ has_mode = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* If we still can't find the mode anywhere, let's add it since it's mandatory
+ * and use default value of 30 ms */
+ if (!has_mode) {
+ FsCodecParameter *newparam = g_new0 (FsCodecParameter, 1);
+ newparam->name = g_strdup ("mode");
+ newparam->value = g_strdup ("30");
+ negotiated_codec->optional_params = g_list_append (
+ negotiated_codec->optional_params, newparam);
+ }
+
+ return negotiated_codec;
+
+ failure:
+ if (negotiated_codec)
+ fs_codec_destroy (negotiated_codec);
+ return NULL;
+
+}
+
+
+
+static FsCodec *
+sdp_is_compat_h263_1998 (GstCaps *rtp_caps, FsCodec *local_codec,
+ FsCodec *remote_codec)
+{
+ FsCodec *negotiated_codec = NULL;
+ GList *mylistitem = NULL, *remote_param_list = NULL;
+ FsCodecParameter *profile = NULL;
+
+ g_debug ("Using H263-1998 negotiation function");
+
+ if (remote_codec->clock_rate != 90000) {
+ g_debug ("Remote clock rate is %d which is not 90000",
+ remote_codec->clock_rate);
+ return NULL;
+ }
+
+
+ if (remote_codec->channels > 1) {
+ g_debug ("Channel count %d > 1", remote_codec->channels);
+ return NULL;
+ }
+
+ /* First lets check if there is a profile */
+
+ for (remote_param_list = remote_codec->optional_params;
+ remote_param_list;
+ remote_param_list = g_list_next (remote_param_list)) {
+ FsCodecParameter *remote_param = remote_param_list->data;
+
+ if (!g_ascii_strcasecmp (remote_param->name, "profile")) {
+
+ if (profile) {
+ g_debug ("The remote codecs contain the profile item more than once, ignoring");
+ return NULL;
+ } else {
+ profile = remote_param;
+ }
+
+ for (mylistitem = local_codec->optional_params;
+ mylistitem;
+ mylistitem = g_list_next (mylistitem)) {
+ FsCodecParameter *local_param = mylistitem->data;
+
+ if (!g_ascii_strcasecmp (local_param->name, "profile")) {
+
+ if (g_ascii_strcasecmp (local_param->value, remote_param->value)) {
+ g_debug ("Local (%s) and remote (%s) profiles are different",
+ local_param->value, remote_param->value);
+ return NULL;
+ } else {
+ g_debug ("We have the same profile, lets return our local codec");
+
+ negotiated_codec = fs_codec_copy (local_codec);
+
+ negotiated_codec->id = remote_codec->id;
+
+ return negotiated_codec;
+ }
+ }
+ }
+ g_debug ("Profile (%s) is unknown locally, rejecting",
+ remote_param->value);
+ return NULL;
+ }
+ }
+
+
+ negotiated_codec = fs_codec_copy (local_codec);
+ return negotiated_codec;
+}
diff --git a/gst/fsrtpconference/fs-rtp-specific-nego.h b/gst/fsrtpconference/fs-rtp-specific-nego.h
new file mode 100644
index 0000000..4d214d1
--- /dev/null
+++ b/gst/fsrtpconference/fs-rtp-specific-nego.h
@@ -0,0 +1,40 @@
+/*
+ * fs-rtp-specific-nego.h - Per-codec SDP negociation
+ *
+ * Farsight RTP/AVP/SAVP/AVPF Module
+ * Copyright (C) 2007 Collabora Ltd.
+ * Copyright (C) 2007 Nokia Corporation
+ * @author Olivier Crete <olivier.crete at collabora.co.uk>
+ *
+ * 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_SPECIFIC_NEGO_H__
+#define __FS_RTP_SPECIFIC_NEGO_H__
+
+#include <glib.h>
+#include <gst/gst.h>
+
+#include <gst/farsight/fs-codec.h>
+
+G_BEGIN_DECLS
+
+FsCodec *
+sdp_is_compat (GstCaps *rtp_caps, FsCodec *local_codec,
+ FsCodec *remote_codec);
+
+G_END_DECLS
+
+#endif
--
1.5.6.5
More information about the farsight-commits
mailing list