Blame gst/fsrtpconference/fs-rtp-dtmf-event-source.c

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
}