|
Packit |
133782 |
/*
|
|
Packit |
133782 |
* Farstream - Farstream RTP DTMF Event Source
|
|
Packit |
133782 |
*
|
|
Packit |
133782 |
* Copyright 2007 Collabora Ltd.
|
|
Packit |
133782 |
* @author: Olivier Crete <olivier.crete@collabora.co.uk>
|
|
Packit |
133782 |
* Copyright 2007 Nokia Corp.
|
|
Packit |
133782 |
*
|
|
Packit |
133782 |
* fs-rtp-dtmf-event-source.c - A Farstream RTP Event Source gobject
|
|
Packit |
133782 |
*
|
|
Packit |
133782 |
* This library is free software; you can redistribute it and/or
|
|
Packit |
133782 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
133782 |
* License as published by the Free Software Foundation; either
|
|
Packit |
133782 |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
133782 |
*
|
|
Packit |
133782 |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
133782 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
133782 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
133782 |
* Lesser General Public License for more details.
|
|
Packit |
133782 |
*
|
|
Packit |
133782 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
133782 |
* License along with this library; if not, write to the Free Software
|
|
Packit |
133782 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
133782 |
*/
|
|
Packit |
133782 |
|
|
Packit |
133782 |
|
|
Packit |
133782 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
133782 |
#include "config.h"
|
|
Packit |
133782 |
#endif
|
|
Packit |
133782 |
|
|
Packit |
133782 |
#include "fs-rtp-dtmf-event-source.h"
|
|
Packit |
133782 |
|
|
Packit |
133782 |
#include <farstream/fs-conference.h>
|
|
Packit |
133782 |
|
|
Packit |
133782 |
#include "fs-rtp-conference.h"
|
|
Packit |
133782 |
#include "fs-rtp-discover-codecs.h"
|
|
Packit |
133782 |
#include "fs-rtp-codec-negotiation.h"
|
|
Packit |
133782 |
|
|
Packit |
133782 |
#define GST_CAT_DEFAULT fsrtpconference_debug
|
|
Packit |
133782 |
|
|
Packit |
133782 |
/*
|
|
Packit |
133782 |
* SECTION:fs-rtp-dtmf-event-source
|
|
Packit |
133782 |
* @short_description: Class to create the source of DTMF events
|
|
Packit |
133782 |
*
|
|
Packit |
133782 |
* This class is manages the DTMF Event source and related matters
|
|
Packit |
133782 |
*
|
|
Packit |
133782 |
*/
|
|
Packit |
133782 |
|
|
Packit |
133782 |
|
|
Packit |
133782 |
/* all privates variables are protected by the mutex */
|
|
Packit |
133782 |
struct _FsRtpDtmfEventSourcePrivate {
|
|
Packit |
133782 |
gboolean disposed;
|
|
Packit |
133782 |
};
|
|
Packit |
133782 |
|
|
Packit |
133782 |
G_DEFINE_TYPE (FsRtpDtmfEventSource, fs_rtp_dtmf_event_source,
|
|
Packit |
133782 |
FS_TYPE_RTP_SPECIAL_SOURCE);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
#define FS_RTP_DTMF_EVENT_SOURCE_GET_PRIVATE(o) \
|
|
Packit |
133782 |
(G_TYPE_INSTANCE_GET_PRIVATE ((o), FS_TYPE_RTP_DTMF_EVENT_SOURCE, \
|
|
Packit |
133782 |
FsRtpDtmfEventSourcePrivate))
|
|
Packit |
133782 |
|
|
Packit |
133782 |
|
|
Packit |
133782 |
static GstElement *
|
|
Packit |
133782 |
fs_rtp_dtmf_event_source_build (FsRtpSpecialSource *source,
|
|
Packit |
133782 |
GList *negotiated_codec_associations,
|
|
Packit |
133782 |
FsCodec *selected_codec);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
|
|
Packit |
133782 |
static GList *fs_rtp_dtmf_event_source_class_add_blueprint (
|
|
Packit |
133782 |
FsRtpSpecialSourceClass *klass,
|
|
Packit |
133782 |
GList *blueprints);
|
|
Packit |
133782 |
static GList *fs_rtp_dtmf_event_source_negotiation_filter (
|
|
Packit |
133782 |
FsRtpSpecialSourceClass *klass,
|
|
Packit |
133782 |
GList *codec_associations);
|
|
Packit |
133782 |
static FsCodec *fs_rtp_dtmf_event_source_get_codec (
|
|
Packit |
133782 |
FsRtpSpecialSourceClass *klass,
|
|
Packit |
133782 |
GList *negotiated_codec_associations,
|
|
Packit |
133782 |
FsCodec *codec);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
static void
|
|
Packit |
133782 |
fs_rtp_dtmf_event_source_class_init (FsRtpDtmfEventSourceClass *klass)
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
FsRtpSpecialSourceClass *spsource_class = FS_RTP_SPECIAL_SOURCE_CLASS (klass);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
spsource_class->build = fs_rtp_dtmf_event_source_build;
|
|
Packit |
133782 |
spsource_class->add_blueprint = fs_rtp_dtmf_event_source_class_add_blueprint;
|
|
Packit |
133782 |
spsource_class->negotiation_filter =
|
|
Packit |
133782 |
fs_rtp_dtmf_event_source_negotiation_filter;
|
|
Packit |
133782 |
spsource_class->get_codec = fs_rtp_dtmf_event_source_get_codec;
|
|
Packit |
133782 |
|
|
Packit |
133782 |
g_type_class_add_private (klass, sizeof (FsRtpDtmfEventSourcePrivate));
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
|
|
Packit |
133782 |
static void
|
|
Packit |
133782 |
fs_rtp_dtmf_event_source_init (FsRtpDtmfEventSource *self)
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
self->priv = FS_RTP_DTMF_EVENT_SOURCE_GET_PRIVATE (self);
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
|
|
Packit |
133782 |
/**
|
|
Packit |
133782 |
* fs_rtp_dtmf_event_source_class_add_blueprint:
|
|
Packit |
133782 |
*
|
|
Packit |
133782 |
* Add one blueprint for telephone-event for each different clock-rate that
|
|
Packit |
133782 |
* exists in the request
|
|
Packit |
133782 |
*/
|
|
Packit |
133782 |
|
|
Packit |
133782 |
static GList*
|
|
Packit |
133782 |
fs_rtp_dtmf_event_source_class_add_blueprint (FsRtpSpecialSourceClass *klass,
|
|
Packit |
133782 |
GList *blueprints)
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
GList *item;
|
|
Packit |
133782 |
GList *already_done = NULL;
|
|
Packit |
133782 |
GstElementFactory *fact = NULL;
|
|
Packit |
133782 |
GList *new_blueprints = NULL;
|
|
Packit |
133782 |
|
|
Packit |
133782 |
fact = gst_element_factory_find ("rtpdtmfsrc");
|
|
Packit |
133782 |
if (fact)
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
gst_object_unref (fact);
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
else
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
GST_CAT_WARNING (fsrtpconference_disco,
|
|
Packit |
133782 |
"Could not find rtpdtmfsrc, will not offer DTMF events");
|
|
Packit |
133782 |
return blueprints;
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
|
|
Packit |
133782 |
fact = gst_element_factory_find ("rtpdtmfdepay");
|
|
Packit |
133782 |
if (!fact)
|
|
Packit |
133782 |
GST_CAT_WARNING (fsrtpconference_disco,
|
|
Packit |
133782 |
"Could not find rtpdtmfdepay, will not be able to receive DTMF events");
|
|
Packit |
133782 |
|
|
Packit |
133782 |
for (item = g_list_first (blueprints);
|
|
Packit |
133782 |
item;
|
|
Packit |
133782 |
item = g_list_next (item))
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
CodecBlueprint *bp = item->data;
|
|
Packit |
133782 |
GList *done_item = NULL;
|
|
Packit |
133782 |
gboolean skip = FALSE;
|
|
Packit |
133782 |
CodecBlueprint *new_bp = NULL;
|
|
Packit |
133782 |
|
|
Packit |
133782 |
if (bp->codec->media_type != FS_MEDIA_TYPE_AUDIO)
|
|
Packit |
133782 |
continue;
|
|
Packit |
133782 |
|
|
Packit |
133782 |
if (!g_ascii_strcasecmp (bp->codec->encoding_name, "telephone-event"))
|
|
Packit |
133782 |
continue;
|
|
Packit |
133782 |
|
|
Packit |
133782 |
if (bp->codec->clock_rate == 0)
|
|
Packit |
133782 |
continue;
|
|
Packit |
133782 |
|
|
Packit |
133782 |
for (done_item = g_list_first (already_done);
|
|
Packit |
133782 |
done_item;
|
|
Packit |
133782 |
done_item = g_list_next (done_item))
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
if (GPOINTER_TO_UINT (done_item->data) == bp->codec->clock_rate)
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
skip = TRUE;
|
|
Packit |
133782 |
break;
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
if (skip)
|
|
Packit |
133782 |
continue;
|
|
Packit |
133782 |
|
|
Packit |
133782 |
new_bp = g_slice_new0 (CodecBlueprint);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
new_bp->codec = fs_codec_new (FS_CODEC_ID_ANY, "telephone-event",
|
|
Packit |
133782 |
FS_MEDIA_TYPE_AUDIO, bp->codec->clock_rate);
|
|
Packit |
133782 |
fs_codec_add_optional_parameter (new_bp->codec, "events", "0-15");
|
|
Packit |
133782 |
new_bp->rtp_caps = fs_codec_to_gst_caps (new_bp->codec);
|
|
Packit |
133782 |
new_bp->media_caps = gst_caps_new_any ();
|
|
Packit |
133782 |
|
|
Packit |
133782 |
if (fact)
|
|
Packit |
133782 |
new_bp->receive_pipeline_factory = g_list_prepend (NULL,
|
|
Packit |
133782 |
g_list_prepend (NULL, gst_object_ref (fact)));
|
|
Packit |
133782 |
|
|
Packit |
133782 |
new_blueprints = g_list_append (new_blueprints, new_bp);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
already_done = g_list_prepend (already_done,
|
|
Packit |
133782 |
GUINT_TO_POINTER (bp->codec->clock_rate));
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
|
|
Packit |
133782 |
if (fact)
|
|
Packit |
133782 |
gst_object_unref (fact);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
g_list_free (already_done);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
blueprints = g_list_concat (blueprints, new_blueprints);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
return blueprints;
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
|
|
Packit |
133782 |
static gboolean
|
|
Packit |
133782 |
_is_telephony_codec (CodecAssociation *ca, gpointer user_data)
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
guint clock_rate = GPOINTER_TO_UINT (user_data);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
if (codec_association_is_valid_for_sending (ca, FALSE) &&
|
|
Packit |
133782 |
ca->codec->media_type == FS_MEDIA_TYPE_AUDIO &&
|
|
Packit |
133782 |
!g_ascii_strcasecmp (ca->codec->encoding_name, "telephone-event") &&
|
|
Packit |
133782 |
ca->codec->clock_rate == clock_rate)
|
|
Packit |
133782 |
return TRUE;
|
|
Packit |
133782 |
else
|
|
Packit |
133782 |
return FALSE;
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
|
|
Packit |
133782 |
/**
|
|
Packit |
133782 |
* fs_rtp_dtmf_event_source_get_codec:
|
|
Packit |
133782 |
* @negotiated_codec_associations: a #GList of currently negotiated
|
|
Packit |
133782 |
* #CodecAssociation
|
|
Packit |
133782 |
* @selected_codec: The current #FsCodec
|
|
Packit |
133782 |
*
|
|
Packit |
133782 |
* Find the telephone-event codec with the proper clock rate in the list
|
|
Packit |
133782 |
*
|
|
Packit |
133782 |
* Returns: The #FsCodec of type "telephone-event" with the requested clock-rate
|
|
Packit |
133782 |
* from the list, or %NULL
|
|
Packit |
133782 |
*/
|
|
Packit |
133782 |
static FsCodec *
|
|
Packit |
133782 |
fs_rtp_dtmf_event_source_get_codec (FsRtpSpecialSourceClass *klass,
|
|
Packit |
133782 |
GList *negotiated_codec_associations, FsCodec *selected_codec)
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
CodecAssociation *ca = NULL;
|
|
Packit |
133782 |
|
|
Packit |
133782 |
if (selected_codec->media_type != FS_MEDIA_TYPE_AUDIO)
|
|
Packit |
133782 |
return NULL;
|
|
Packit |
133782 |
|
|
Packit |
133782 |
ca = lookup_codec_association_custom (negotiated_codec_associations,
|
|
Packit |
133782 |
_is_telephony_codec, GUINT_TO_POINTER (selected_codec->clock_rate));
|
|
Packit |
133782 |
|
|
Packit |
133782 |
if (ca)
|
|
Packit |
133782 |
return ca->send_codec;
|
|
Packit |
133782 |
else
|
|
Packit |
133782 |
return NULL;
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
|
|
Packit |
133782 |
static GstElement *
|
|
Packit |
133782 |
fs_rtp_dtmf_event_source_build (FsRtpSpecialSource *source,
|
|
Packit |
133782 |
GList *negotiated_codec_associations,
|
|
Packit |
133782 |
FsCodec *selected_codec)
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
FsCodec *telephony_codec = NULL;
|
|
Packit |
133782 |
GstCaps *caps = NULL;
|
|
Packit |
133782 |
GstPad *pad = NULL;
|
|
Packit |
133782 |
GstElement *dtmfsrc = NULL;
|
|
Packit |
133782 |
GstElement *capsfilter = NULL;
|
|
Packit |
133782 |
GstPad *ghostpad = NULL;
|
|
Packit |
133782 |
GstElement *bin = NULL;
|
|
Packit |
133782 |
|
|
Packit |
133782 |
telephony_codec = fs_rtp_dtmf_event_source_get_codec (
|
|
Packit |
133782 |
FS_RTP_SPECIAL_SOURCE_GET_CLASS(source), negotiated_codec_associations,
|
|
Packit |
133782 |
selected_codec);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
g_return_val_if_fail (telephony_codec, NULL);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
source->codec = fs_codec_copy (telephony_codec);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
bin = gst_bin_new (NULL);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
GST_DEBUG ("Creating telephone-event source for " FS_CODEC_FORMAT,
|
|
Packit |
133782 |
FS_CODEC_ARGS (telephony_codec));
|
|
Packit |
133782 |
|
|
Packit |
133782 |
dtmfsrc = gst_element_factory_make ("rtpdtmfsrc", NULL);
|
|
Packit |
133782 |
if (!dtmfsrc)
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
GST_ERROR ("Could not make rtpdtmfsrc");
|
|
Packit |
133782 |
goto error;
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
if (!gst_bin_add (GST_BIN (bin), dtmfsrc))
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
GST_ERROR ("Could not add rtpdtmfsrc to bin");
|
|
Packit |
133782 |
gst_object_unref (dtmfsrc);
|
|
Packit |
133782 |
goto error;
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
|
|
Packit |
133782 |
capsfilter = gst_element_factory_make ("capsfilter", NULL);
|
|
Packit |
133782 |
if (!capsfilter)
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
GST_ERROR ("Could not make capsfilter");
|
|
Packit |
133782 |
goto error;
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
if (!gst_bin_add (GST_BIN (bin), capsfilter))
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
GST_ERROR ("Could not add capsfilter to bin");
|
|
Packit |
133782 |
gst_object_unref (capsfilter);
|
|
Packit |
133782 |
goto error;
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
|
|
Packit |
133782 |
caps = fs_codec_to_gst_caps (telephony_codec);
|
|
Packit |
133782 |
g_object_set (capsfilter, "caps", caps, NULL);
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
gchar *str = gst_caps_to_string (caps);
|
|
Packit |
133782 |
GST_DEBUG ("Using caps %s for dtmf", str);
|
|
Packit |
133782 |
g_free (str);
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
gst_caps_unref (caps);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
if (!gst_element_link_pads (dtmfsrc, "src", capsfilter, "sink"))
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
GST_ERROR ("Could not link the rtpdtmfsrc and its capsfilter");
|
|
Packit |
133782 |
goto error;
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
|
|
Packit |
133782 |
pad = gst_element_get_static_pad (capsfilter, "src");
|
|
Packit |
133782 |
if (!pad)
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
GST_ERROR ("Could not get \"src\" pad from capsfilter");
|
|
Packit |
133782 |
goto error;
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
ghostpad = gst_ghost_pad_new ("src", pad);
|
|
Packit |
133782 |
if (!ghostpad)
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
GST_ERROR ("Could not create a ghostpad for capsfilter src pad for"
|
|
Packit |
133782 |
" rtpdtmfsrc");
|
|
Packit |
133782 |
goto error;
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
if (!gst_element_add_pad (bin, ghostpad))
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
GST_ERROR ("Could not get \"src\" ghostpad to dtmf source bin");
|
|
Packit |
133782 |
gst_object_unref (pad);
|
|
Packit |
133782 |
goto error;
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
gst_object_unref (pad);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
return bin;
|
|
Packit |
133782 |
|
|
Packit |
133782 |
error:
|
|
Packit |
133782 |
gst_object_unref (bin);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
return NULL;
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
|
|
Packit |
133782 |
/*
|
|
Packit |
133782 |
* This looks if there is a non-disabled codec with the requested clock rate
|
|
Packit |
133782 |
* other than telephone-event.
|
|
Packit |
133782 |
*/
|
|
Packit |
133782 |
|
|
Packit |
133782 |
static gboolean
|
|
Packit |
133782 |
has_rate (CodecAssociation *ca, gpointer user_data)
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
guint clock_rate = GPOINTER_TO_UINT (user_data);
|
|
Packit |
133782 |
|
|
Packit |
133782 |
if (ca->codec->clock_rate == clock_rate &&
|
|
Packit |
133782 |
!ca->recv_only &&
|
|
Packit |
133782 |
g_ascii_strcasecmp (ca->codec->encoding_name, "telephone-event"))
|
|
Packit |
133782 |
return TRUE;
|
|
Packit |
133782 |
else
|
|
Packit |
133782 |
return FALSE;
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
|
|
Packit |
133782 |
static GList *
|
|
Packit |
133782 |
fs_rtp_dtmf_event_source_negotiation_filter (FsRtpSpecialSourceClass *klass,
|
|
Packit |
133782 |
GList *codec_associations)
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
GList *tmp;
|
|
Packit |
133782 |
|
|
Packit |
133782 |
for (tmp = codec_associations; tmp; tmp = g_list_next (tmp))
|
|
Packit |
133782 |
{
|
|
Packit |
133782 |
CodecAssociation *ca = tmp->data;
|
|
Packit |
133782 |
|
|
Packit |
133782 |
/* Ignore disabled or non telephone-event codecs*/
|
|
Packit |
133782 |
if (ca->disable || ca->reserved || ca->recv_only ||
|
|
Packit |
133782 |
g_ascii_strcasecmp (ca->codec->encoding_name, "telephone-event"))
|
|
Packit |
133782 |
continue;
|
|
Packit |
133782 |
|
|
Packit |
133782 |
/* Lets disable telephone-event codecs where we don't find */
|
|
Packit |
133782 |
if (!lookup_codec_association_custom (codec_associations, has_rate,
|
|
Packit |
133782 |
GUINT_TO_POINTER (ca->codec->clock_rate)))
|
|
Packit |
133782 |
ca->disable = TRUE;
|
|
Packit |
133782 |
}
|
|
Packit |
133782 |
|
|
Packit |
133782 |
return codec_associations;
|
|
Packit |
133782 |
}
|