Blame transmitters/nice/fs-nice-stream-transmitter.c

Packit 133782
/*
Packit 133782
 * Farstream - Farstream libnice Stream Transmitter
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-nice-stream-transmitter.c - A Farstream libnice stream transmitter
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
/**
Packit 133782
 * SECTION:fs-nice-stream-transmitter
Packit 133782
 * @short_description: A stream transmitter object for ICE using libnice
Packit 133782
 * @see_also: #FsRawUdpStreamTransmitter
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-nice-stream-transmitter.h"
Packit 133782
#include "fs-nice-transmitter.h"
Packit 133782
#include "fs-nice-agent.h"
Packit 133782
Packit 133782
#include <farstream/fs-conference.h>
Packit 133782
Packit 133782
#include <gst/gst.h>
Packit 133782
Packit 133782
#include <string.h>
Packit 133782
#include <sys/types.h>
Packit 133782
Packit 133782
#define GST_CAT_DEFAULT fs_nice_transmitter_debug
Packit 133782
Packit 133782
/* Signals */
Packit 133782
enum
Packit 133782
{
Packit 133782
  LAST_SIGNAL
Packit 133782
};
Packit 133782
Packit 133782
/* props */
Packit 133782
enum
Packit 133782
{
Packit 133782
  PROP_0,
Packit 133782
  PROP_SENDING,
Packit 133782
  PROP_PREFERRED_LOCAL_CANDIDATES,
Packit 133782
  PROP_STUN_IP,
Packit 133782
  PROP_STUN_PORT,
Packit 133782
  PROP_CONTROLLING_MODE,
Packit 133782
  PROP_STREAM_ID,
Packit 133782
  PROP_COMPATIBILITY_MODE,
Packit 133782
  PROP_ASSOCIATE_ON_SOURCE,
Packit 133782
  PROP_RELAY_INFO,
Packit 133782
  PROP_MIN_PORT,
Packit 133782
  PROP_MAX_PORT,
Packit 133782
  PROP_ICE_TCP,
Packit 133782
  PROP_ICE_UDP,
Packit 133782
  PROP_RELIABLE,
Packit 133782
  PROP_DEBUG,
Packit 133782
  PROP_SEND_COMPONENT_MUX
Packit 133782
};
Packit 133782
Packit 133782
struct _FsNiceStreamTransmitterPrivate
Packit 133782
{
Packit 133782
  FsNiceTransmitter *transmitter;
Packit 133782
Packit 133782
  FsNiceAgent *agent;
Packit 133782
Packit 133782
  guint stream_id;
Packit 133782
Packit 133782
  guint min_port;
Packit 133782
  guint max_port;
Packit 133782
Packit 133782
  gchar *stun_ip;
Packit 133782
  guint stun_port;
Packit 133782
Packit 133782
  gboolean controlling_mode;
Packit 133782
  gboolean ice_udp;
Packit 133782
  gboolean ice_tcp;
Packit 133782
  gboolean reliable;
Packit 133782
  gboolean send_component_mux;
Packit 133782
Packit 133782
  guint compatibility_mode;
Packit 133782
Packit 133782
  GMutex mutex;
Packit 133782
Packit 133782
  GList *preferred_local_candidates;
Packit 133782
Packit 133782
  gulong state_changed_handler_id;
Packit 133782
  gulong gathering_done_handler_id;
Packit 133782
  gulong new_selected_pair_handler_id;
Packit 133782
  gulong new_candidate_handler_id;
Packit 133782
Packit 133782
  gulong tos_changed_handler_id;
Packit 133782
Packit 133782
  GPtrArray *relay_info;
Packit 133782
Packit 133782
  volatile gint associate_on_source;
Packit 133782
Packit 133782
  gboolean *component_has_been_ready; /* only from NiceAgent main thread */
Packit 133782
Packit 133782
  /* Everything below is protected by the mutex */
Packit 133782
Packit 133782
  gboolean sending;
Packit 133782
Packit 133782
  gboolean forced_candidates;
Packit 133782
  GList *remote_candidates;
Packit 133782
  GList *local_candidates;
Packit 133782
Packit 133782
  /* These are fixed and must be identical in the latest draft */
Packit 133782
  gchar *username;
Packit 133782
  gchar *password;
Packit 133782
Packit 133782
  gboolean gathered;
Packit 133782
Packit 133782
  NiceGstStream *gststream;
Packit 133782
};
Packit 133782
Packit 133782
#define FS_NICE_STREAM_TRANSMITTER_GET_PRIVATE(o)  \
Packit 133782
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), FS_TYPE_NICE_STREAM_TRANSMITTER, \
Packit 133782
                                FsNiceStreamTransmitterPrivate))
Packit 133782
Packit 133782
#define FS_NICE_STREAM_TRANSMITTER_LOCK(o)   g_mutex_lock (&(o)->priv->mutex)
Packit 133782
#define FS_NICE_STREAM_TRANSMITTER_UNLOCK(o) g_mutex_unlock (&(o)->priv->mutex)
Packit 133782
Packit 133782
Packit 133782
static void fs_nice_stream_transmitter_class_init (FsNiceStreamTransmitterClass *klass);
Packit 133782
static void fs_nice_stream_transmitter_init (FsNiceStreamTransmitter *self);
Packit 133782
static void fs_nice_stream_transmitter_dispose (GObject *object);
Packit 133782
static void fs_nice_stream_transmitter_finalize (GObject *object);
Packit 133782
Packit 133782
static void fs_nice_stream_transmitter_get_property (GObject *object,
Packit 133782
                                                guint prop_id,
Packit 133782
                                                GValue *value,
Packit 133782
                                                GParamSpec *pspec);
Packit 133782
static void fs_nice_stream_transmitter_set_property (GObject *object,
Packit 133782
                                                guint prop_id,
Packit 133782
                                                const GValue *value,
Packit 133782
                                                GParamSpec *pspec);
Packit 133782
Packit 133782
static gboolean fs_nice_stream_transmitter_add_remote_candidates (
Packit 133782
    FsStreamTransmitter *streamtransmitter, GList *candidates,
Packit 133782
    GError **error);
Packit 133782
static gboolean fs_nice_stream_transmitter_force_remote_candidates (
Packit 133782
    FsStreamTransmitter *streamtransmitter,
Packit 133782
    GList *remote_candidates,
Packit 133782
    GError **error);
Packit 133782
static gboolean fs_nice_stream_transmitter_gather_local_candidates (
Packit 133782
    FsStreamTransmitter *streamtransmitter,
Packit 133782
    GError **error);
Packit 133782
static void fs_nice_stream_transmitter_stop (
Packit 133782
    FsStreamTransmitter *streamtransmitter);
Packit 133782
Packit 133782
static void agent_state_changed (NiceAgent *agent,
Packit 133782
    guint stream_id,
Packit 133782
    guint component_id,
Packit 133782
    guint state,
Packit 133782
    gpointer user_data);
Packit 133782
static void agent_gathering_done (NiceAgent *agent, guint stream_id,
Packit 133782
    gpointer user_data);
Packit 133782
static void agent_new_selected_pair (NiceAgent *agent,
Packit 133782
    guint stream_id,
Packit 133782
    guint component_id,
Packit 133782
    const gchar *lfoundation,
Packit 133782
    const gchar *rfoundation,
Packit 133782
    gpointer user_data);
Packit 133782
static void agent_new_candidate (NiceAgent *agent,
Packit 133782
    guint stream_id,
Packit 133782
    guint component_id,
Packit 133782
    const gchar *foundation,
Packit 133782
    gpointer user_data);
Packit 133782
Packit 133782
static GstPadProbeReturn known_buffer_have_buffer_handler (GstPad *pad,
Packit 133782
    GstPadProbeInfo *info,
Packit 133782
    gpointer user_data);
Packit 133782
Packit 133782
Packit 133782
static GObjectClass *parent_class = NULL;
Packit 133782
// static guint signals[LAST_SIGNAL] = { 0 };
Packit 133782
Packit 133782
static GType type = 0;
Packit 133782
Packit 133782
Packit 133782
GType
Packit 133782
fs_nice_stream_transmitter_get_type (void)
Packit 133782
{
Packit 133782
  return type;
Packit 133782
}
Packit 133782
Packit 133782
GType
Packit 133782
fs_nice_stream_transmitter_register_type (FsPlugin *module G_GNUC_UNUSED)
Packit 133782
{
Packit 133782
  static const GTypeInfo info = {
Packit 133782
    sizeof (FsNiceStreamTransmitterClass),
Packit 133782
    NULL,
Packit 133782
    NULL,
Packit 133782
    (GClassInitFunc) fs_nice_stream_transmitter_class_init,
Packit 133782
    NULL,
Packit 133782
    NULL,
Packit 133782
    sizeof (FsNiceStreamTransmitter),
Packit 133782
    0,
Packit 133782
    (GInstanceInitFunc) fs_nice_stream_transmitter_init
Packit 133782
  };
Packit 133782
Packit 133782
  type = g_type_register_static (FS_TYPE_STREAM_TRANSMITTER,
Packit 133782
      "FsNiceStreamTransmitter", &info, 0);
Packit 133782
Packit 133782
  return type;
Packit 133782
}
Packit 133782
Packit 133782
static void
Packit 133782
fs_nice_stream_transmitter_class_init (FsNiceStreamTransmitterClass *klass)
Packit 133782
{
Packit 133782
  GObjectClass *gobject_class = (GObjectClass *) klass;
Packit 133782
  FsStreamTransmitterClass *streamtransmitterclass =
Packit 133782
    FS_STREAM_TRANSMITTER_CLASS (klass);
Packit 133782
Packit 133782
  parent_class = g_type_class_peek_parent (klass);
Packit 133782
Packit 133782
  gobject_class->set_property = fs_nice_stream_transmitter_set_property;
Packit 133782
  gobject_class->get_property = fs_nice_stream_transmitter_get_property;
Packit 133782
  gobject_class->dispose = fs_nice_stream_transmitter_dispose;
Packit 133782
  gobject_class->finalize = fs_nice_stream_transmitter_finalize;
Packit 133782
Packit 133782
  streamtransmitterclass->add_remote_candidates =
Packit 133782
    fs_nice_stream_transmitter_add_remote_candidates;
Packit 133782
  streamtransmitterclass->force_remote_candidates =
Packit 133782
    fs_nice_stream_transmitter_force_remote_candidates;
Packit 133782
  streamtransmitterclass->gather_local_candidates =
Packit 133782
    fs_nice_stream_transmitter_gather_local_candidates;
Packit 133782
  streamtransmitterclass->stop =
Packit 133782
    fs_nice_stream_transmitter_stop;
Packit 133782
Packit 133782
  g_type_class_add_private (klass, sizeof (FsNiceStreamTransmitterPrivate));
Packit 133782
Packit 133782
  g_object_class_override_property (gobject_class, PROP_SENDING, "sending");
Packit 133782
  g_object_class_override_property (gobject_class,
Packit 133782
      PROP_PREFERRED_LOCAL_CANDIDATES, "preferred-local-candidates");
Packit 133782
  g_object_class_override_property (gobject_class, PROP_ASSOCIATE_ON_SOURCE,
Packit 133782
      "associate-on-source");
Packit 133782
Packit 133782
  g_object_class_install_property (gobject_class, PROP_STUN_IP,
Packit 133782
      g_param_spec_string (
Packit 133782
          "stun-ip",
Packit 133782
          "STUN server",
Packit 133782
          "The STUN server used to obtain server-reflexive candidates",
Packit 133782
          NULL,
Packit 133782
          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
Packit 133782
Packit 133782
  g_object_class_install_property (gobject_class, PROP_STUN_PORT,
Packit 133782
      g_param_spec_uint (
Packit 133782
          "stun-port",
Packit 133782
          "STUN server port",
Packit 133782
          "The STUN server used to obtain server-reflexive candidates",
Packit 133782
          0, 65536,
Packit 133782
          3478,
Packit 133782
          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
Packit 133782
Packit 133782
  g_object_class_install_property (gobject_class, PROP_CONTROLLING_MODE,
Packit 133782
      g_param_spec_boolean (
Packit 133782
          "controlling-mode",
Packit 133782
          "ICE controlling mode",
Packit 133782
          "Whether the agent is in controlling mode",
Packit 133782
          TRUE,
Packit 133782
          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
Packit 133782
Packit 133782
  g_object_class_install_property (gobject_class, PROP_ICE_UDP,
Packit 133782
      g_param_spec_boolean (
Packit 133782
          "ice-udp",
Packit 133782
          "ICE UDP",
Packit 133782
          "Whether the agent gathers UDP candidates",
Packit 133782
          TRUE,
Packit 133782
          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
Packit 133782
Packit 133782
  g_object_class_install_property (gobject_class, PROP_ICE_TCP,
Packit 133782
      g_param_spec_boolean (
Packit 133782
          "ice-tcp",
Packit 133782
          "ICE TCP",
Packit 133782
          "Whether the agent gathers TCP candidates",
Packit 133782
          TRUE,
Packit 133782
          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
Packit 133782
Packit 133782
  g_object_class_install_property (gobject_class, PROP_RELIABLE,
Packit 133782
      g_param_spec_boolean (
Packit 133782
          "reliable",
Packit 133782
          "reliable mode",
Packit 133782
          "Whether the agent is reliable",
Packit 133782
          FALSE,
Packit 133782
          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
Packit 133782
Packit 133782
  g_object_class_install_property (gobject_class, PROP_STREAM_ID,
Packit 133782
      g_param_spec_uint (
Packit 133782
          "stream-id",
Packit 133782
          "The id of the stream",
Packit 133782
          "The id of the stream according to libnice",
Packit 133782
          0, G_MAXINT,
Packit 133782
          0,
Packit 133782
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Packit 133782
Packit 133782
  g_object_class_install_property (gobject_class, PROP_COMPATIBILITY_MODE,
Packit 133782
      g_param_spec_uint (
Packit 133782
          "compatibility-mode",
Packit 133782
          "The compability-mode",
Packit 133782
          "The id of the stream according to libnice",
Packit 133782
          NICE_COMPATIBILITY_DRAFT19, NICE_COMPATIBILITY_LAST,
Packit 133782
          NICE_COMPATIBILITY_DRAFT19,
Packit 133782
          G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
Packit 133782
Packit 133782
  /**
Packit 133782
   * FsNiceStreamTransmitter:relay-info:
Packit 133782
   *
Packit 133782
   * This is a #GPtrArray containing one or more #GstStructure.
Packit 133782
   *
Packit 133782
   * The fields in the structure are:
Packit 133782
   *  <informaltable>
Packit 133782
   *   Required
Packit 133782
   *   
Packit 133782
   *     (gchar*)
Packit 133782
   *     ip
Packit 133782
   *     The IP address of the TURN server
Packit 133782
   *   
Packit 133782
   *   
Packit 133782
   *     (guint)
Packit 133782
   *     port
Packit 133782
   *     The port of the TURN server
Packit 133782
   *   
Packit 133782
   *   
Packit 133782
   *     (gchar*)
Packit 133782
   *     username
Packit 133782
   *   
Packit 133782
   *   
Packit 133782
   *     (gchar*)
Packit 133782
   *     password
Packit 133782
   *   
Packit 133782
   *   Optional
Packit 133782
   *   
Packit 133782
   *    (gchar *)
Packit 133782
   *    relay-type
Packit 133782
   *    The type of TURN server, can use "udp", "tcp" or "tls".
Packit 133782
   *        Defaults to "udp" if not specified.
Packit 133782
   *   
Packit 133782
   *   
Packit 133782
   *    (guint)
Packit 133782
   *    component
Packit 133782
   *    The component this TURN server and creditials will be used for.
Packit 133782
   *    If no component is specified, it will be used for all components where
Packit 133782
   *    no per-component details were specified.
Packit 133782
   *    This is useful if you want to specify different short term creditial
Packit 133782
   *    username/password combinations for Google and MSN compatibility modes.
Packit 133782
   *    
Packit 133782
   *   
Packit 133782
   *  </informaltable>
Packit 133782
   *
Packit 133782
   * Example:
Packit 133782
   * |[
Packit 133782
   GPtrArray *relay_info = g_ptr_array_new_full (1, (GDestroyNotify) gst_structure_free);
Packit 133782
   g_ptr_array_add (relay_info,
Packit 133782
      gst_structure_new ("aa",
Packit 133782
          "ip", G_TYPE_STRING, "127.0.0.1",
Packit 133782
          "port", G_TYPE_UINT, 7654,
Packit 133782
          "username", G_TYPE_STRING, "blah",
Packit 133782
          "password", G_TYPE_STRING, "blah2",
Packit 133782
          "relay-type", G_TYPE_STRING, "udp",
Packit 133782
          NULL));
Packit 133782
   |]
Packit 133782
   *
Packit 133782
   */
Packit 133782
Packit 133782
  g_object_class_install_property (gobject_class, PROP_RELAY_INFO,
Packit 133782
      g_param_spec_boxed (
Packit 133782
          "relay-info",
Packit 133782
          "Information for the TURN server",
Packit 133782
          "ip/port/username/password/relay-type/component of the TURN servers"
Packit 133782
          " in a GPtrArray of GstStructures",
Packit 133782
          G_TYPE_PTR_ARRAY,
Packit 133782
          G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
Packit 133782
Packit 133782
  g_object_class_install_property (gobject_class, PROP_DEBUG,
Packit 133782
      g_param_spec_boolean (
Packit 133782
          "debug",
Packit 133782
          "Enable debug messages",
Packit 133782
          "Whether the agent should enable libnice and stun debug messages",
Packit 133782
          FALSE,
Packit 133782
          G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
Packit 133782
Packit 133782
  g_object_class_install_property (gobject_class, PROP_MIN_PORT,
Packit 133782
      g_param_spec_uint (
Packit 133782
          "min-port",
Packit 133782
          "Minimal listen port",
Packit 133782
          "Minimal port number for allocating host candidates."
Packit 133782
          " 0 means use any port",
Packit 133782
          0, 65535,
Packit 133782
          0,
Packit 133782
          G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
Packit 133782
Packit 133782
  g_object_class_install_property (gobject_class, PROP_MAX_PORT,
Packit 133782
      g_param_spec_uint (
Packit 133782
          "max-port",
Packit 133782
          "Maximal listen port",
Packit 133782
          "Maximal port number for allocating host candidates."
Packit 133782
          " It should apply that min-port < max-port; otherwise, any port is"
Packit 133782
          " used, just as when the value is 0",
Packit 133782
          0, 65535,
Packit 133782
          0,
Packit 133782
          G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
Packit 133782
Packit 133782
  g_object_class_install_property (gobject_class, PROP_SEND_COMPONENT_MUX,
Packit 133782
      g_param_spec_boolean (
Packit 133782
          "send-component-mux",
Packit 133782
          "Send component mux",
Packit 133782
          "Whether to mux all components on the same component as component 1",
Packit 133782
          FALSE,
Packit 133782
          G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
Packit 133782
Packit 133782
}
Packit 133782
Packit 133782
static void
Packit 133782
fs_nice_stream_transmitter_init (FsNiceStreamTransmitter *self)
Packit 133782
{
Packit 133782
  /* member init */
Packit 133782
  self->priv = FS_NICE_STREAM_TRANSMITTER_GET_PRIVATE (self);
Packit 133782
Packit 133782
  self->priv->sending = TRUE;
Packit 133782
  g_mutex_init (&self->priv->mutex);
Packit 133782
Packit 133782
  self->priv->controlling_mode = TRUE;
Packit 133782
  self->priv->ice_udp = TRUE;
Packit 133782
  self->priv->ice_tcp = TRUE;
Packit 133782
  self->priv->reliable = TRUE;
Packit 133782
}
Packit 133782
Packit 133782
static void
Packit 133782
fs_nice_stream_transmitter_dispose (GObject *object)
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (object);
Packit 133782
Packit 133782
  fs_nice_stream_transmitter_stop (FS_STREAM_TRANSMITTER_CAST (object));
Packit 133782
Packit 133782
  FS_NICE_STREAM_TRANSMITTER_LOCK (self);
Packit 133782
  if (self->priv->state_changed_handler_id)
Packit 133782
    g_signal_handler_disconnect (self->priv->agent->agent,
Packit 133782
        self->priv->state_changed_handler_id);
Packit 133782
  self->priv->state_changed_handler_id = 0;
Packit 133782
Packit 133782
  if (self->priv->gathering_done_handler_id)
Packit 133782
    g_signal_handler_disconnect (self->priv->agent->agent,
Packit 133782
        self->priv->gathering_done_handler_id);
Packit 133782
  self->priv->gathering_done_handler_id = 0;
Packit 133782
Packit 133782
  if (self->priv->new_selected_pair_handler_id)
Packit 133782
    g_signal_handler_disconnect (self->priv->agent->agent,
Packit 133782
        self->priv->new_selected_pair_handler_id);
Packit 133782
  self->priv->new_selected_pair_handler_id = 0;
Packit 133782
Packit 133782
  if (self->priv->new_candidate_handler_id)
Packit 133782
    g_signal_handler_disconnect (self->priv->agent->agent,
Packit 133782
        self->priv->new_candidate_handler_id);
Packit 133782
  self->priv->new_candidate_handler_id = 0;
Packit 133782
Packit 133782
  if (self->priv->tos_changed_handler_id)
Packit 133782
    g_signal_handler_disconnect (self->priv->transmitter,
Packit 133782
        self->priv->tos_changed_handler_id);
Packit 133782
  self->priv->tos_changed_handler_id = 0;
Packit 133782
Packit 133782
  if (self->priv->agent)
Packit 133782
  {
Packit 133782
    g_object_unref (self->priv->agent);
Packit 133782
    self->priv->agent = NULL;
Packit 133782
  }
Packit 133782
  FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
Packit 133782
  if (self->priv->transmitter)
Packit 133782
  {
Packit 133782
    g_object_unref (self->priv->transmitter);
Packit 133782
    self->priv->transmitter = NULL;
Packit 133782
  }
Packit 133782
Packit 133782
  parent_class->dispose (object);
Packit 133782
}
Packit 133782
Packit 133782
static void
Packit 133782
fs_nice_stream_transmitter_stop (FsStreamTransmitter *streamtransmitter)
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *self =
Packit 133782
    FS_NICE_STREAM_TRANSMITTER (streamtransmitter);
Packit 133782
  NiceGstStream *gststream;
Packit 133782
  guint stream_id;
Packit 133782
Packit 133782
Packit 133782
  FS_NICE_STREAM_TRANSMITTER_LOCK (self);
Packit 133782
  gststream = self->priv->gststream;
Packit 133782
  self->priv->gststream = NULL;
Packit 133782
  stream_id = self->priv->stream_id;
Packit 133782
  /* We can't unset the stream id because it gets messy fast, just leave it as
Packit 133782
   * is, all calls should fail anyway
Packit 133782
   */
Packit 133782
  FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
Packit 133782
  if (gststream)
Packit 133782
    fs_nice_transmitter_free_gst_stream (self->priv->transmitter, gststream);
Packit 133782
  if (stream_id)
Packit 133782
    nice_agent_remove_stream (self->priv->agent->agent, stream_id);
Packit 133782
}
Packit 133782
Packit 133782
Packit 133782
static void
Packit 133782
fs_nice_stream_transmitter_finalize (GObject *object)
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (object);
Packit 133782
Packit 133782
  fs_candidate_list_destroy (self->priv->preferred_local_candidates);
Packit 133782
Packit 133782
  fs_candidate_list_destroy (self->priv->remote_candidates);
Packit 133782
  fs_candidate_list_destroy (self->priv->local_candidates);
Packit 133782
Packit 133782
  if (self->priv->relay_info)
Packit 133782
    g_ptr_array_unref (self->priv->relay_info);
Packit 133782
Packit 133782
  g_free (self->priv->stun_ip);
Packit 133782
Packit 133782
  g_mutex_clear (&self->priv->mutex);
Packit 133782
Packit 133782
  g_free (self->priv->username);
Packit 133782
  g_free (self->priv->password);
Packit 133782
Packit 133782
  g_free (self->priv->component_has_been_ready);
Packit 133782
Packit 133782
  parent_class->finalize (object);
Packit 133782
}
Packit 133782
Packit 133782
static void
Packit 133782
fs_nice_stream_transmitter_get_property (GObject *object,
Packit 133782
                                           guint prop_id,
Packit 133782
                                           GValue *value,
Packit 133782
                                           GParamSpec *pspec)
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (object);
Packit 133782
Packit 133782
  switch (prop_id)
Packit 133782
  {
Packit 133782
    case PROP_SENDING:
Packit 133782
      FS_NICE_STREAM_TRANSMITTER_LOCK (self);
Packit 133782
      g_value_set_boolean (value, self->priv->sending);
Packit 133782
      FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
      break;
Packit 133782
    case PROP_PREFERRED_LOCAL_CANDIDATES:
Packit 133782
      g_value_set_boxed (value, self->priv->preferred_local_candidates);
Packit 133782
      break;
Packit 133782
    case PROP_STUN_IP:
Packit 133782
      if (self->priv->agent)
Packit 133782
        g_object_get_property (G_OBJECT (self->priv->agent->agent),
Packit 133782
            g_param_spec_get_name (pspec), value);
Packit 133782
      else
Packit 133782
        g_value_set_string (value, self->priv->stun_ip);
Packit 133782
      break;
Packit 133782
    case PROP_STUN_PORT:
Packit 133782
      if (self->priv->agent)
Packit 133782
        g_object_get_property (G_OBJECT (self->priv->agent->agent),
Packit 133782
            g_param_spec_get_name (pspec), value);
Packit 133782
      else
Packit 133782
        g_value_set_uint (value, self->priv->stun_port);
Packit 133782
      break;
Packit 133782
    case PROP_CONTROLLING_MODE:
Packit 133782
      if (self->priv->agent)
Packit 133782
        g_object_get_property (G_OBJECT (self->priv->agent->agent),
Packit 133782
            g_param_spec_get_name (pspec), value);
Packit 133782
      else
Packit 133782
        g_value_set_boolean (value, self->priv->controlling_mode);
Packit 133782
      break;
Packit 133782
    case PROP_ICE_UDP:
Packit 133782
      if (self->priv->agent)
Packit 133782
        g_object_get_property (G_OBJECT (self->priv->agent->agent),
Packit 133782
            g_param_spec_get_name (pspec), value);
Packit 133782
      else
Packit 133782
        g_value_set_boolean (value, self->priv->ice_udp);
Packit 133782
      break;
Packit 133782
    case PROP_ICE_TCP:
Packit 133782
      if (self->priv->agent)
Packit 133782
        g_object_get_property (G_OBJECT (self->priv->agent->agent),
Packit 133782
            g_param_spec_get_name (pspec), value);
Packit 133782
      else
Packit 133782
        g_value_set_boolean (value, self->priv->ice_tcp);
Packit 133782
      break;
Packit 133782
    case PROP_RELIABLE:
Packit 133782
      if (self->priv->agent)
Packit 133782
        g_object_get_property (G_OBJECT (self->priv->agent->agent),
Packit 133782
            g_param_spec_get_name (pspec), value);
Packit 133782
      else
Packit 133782
        g_value_set_boolean (value, self->priv->reliable);
Packit 133782
      break;
Packit 133782
    case PROP_STREAM_ID:
Packit 133782
      FS_NICE_STREAM_TRANSMITTER_LOCK (self);
Packit 133782
      g_value_set_uint (value, self->priv->stream_id);
Packit 133782
      FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
      break;
Packit 133782
    case PROP_COMPATIBILITY_MODE:
Packit 133782
      g_value_set_uint (value, self->priv->compatibility_mode);
Packit 133782
      break;
Packit 133782
    case PROP_ASSOCIATE_ON_SOURCE:
Packit 133782
      g_value_set_boolean (value,
Packit 133782
          g_atomic_int_get (&self->priv->associate_on_source));
Packit 133782
      break;
Packit 133782
    case PROP_SEND_COMPONENT_MUX:
Packit 133782
      g_value_set_boolean (value, self->priv->send_component_mux);
Packit 133782
      break;
Packit 133782
    default:
Packit 133782
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 133782
      break;
Packit 133782
  }
Packit 133782
}
Packit 133782
Packit 133782
static void
Packit 133782
fs_nice_stream_transmitter_set_property (GObject *object,
Packit 133782
                                           guint prop_id,
Packit 133782
                                           const GValue *value,
Packit 133782
                                           GParamSpec *pspec)
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (object);
Packit 133782
Packit 133782
  switch (prop_id)
Packit 133782
  {
Packit 133782
    case PROP_SENDING:
Packit 133782
      FS_NICE_STREAM_TRANSMITTER_LOCK (self);
Packit 133782
      self->priv->sending = g_value_get_boolean (value);
Packit 133782
      if (self->priv->gststream)
Packit 133782
        fs_nice_transmitter_set_sending (self->priv->transmitter,
Packit 133782
            self->priv->gststream, g_value_get_boolean (value));
Packit 133782
      FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
      break;
Packit 133782
    case PROP_PREFERRED_LOCAL_CANDIDATES:
Packit 133782
      self->priv->preferred_local_candidates = g_value_dup_boxed (value);
Packit 133782
      break;
Packit 133782
    case PROP_STUN_IP:
Packit 133782
      self->priv->stun_ip = g_value_dup_string (value);
Packit 133782
      break;
Packit 133782
    case PROP_STUN_PORT:
Packit 133782
      self->priv->stun_port = g_value_get_uint (value);
Packit 133782
      break;
Packit 133782
    case PROP_CONTROLLING_MODE:
Packit 133782
      self->priv->controlling_mode = g_value_get_boolean (value);
Packit 133782
      if (self->priv->transmitter && self->priv->agent)
Packit 133782
        g_object_set_property (G_OBJECT (self->priv->agent->agent),
Packit 133782
            g_param_spec_get_name (pspec), value);
Packit 133782
      break;
Packit 133782
    case PROP_ICE_UDP:
Packit 133782
      self->priv->ice_udp = g_value_get_boolean (value);
Packit 133782
      if (self->priv->transmitter && self->priv->agent)
Packit 133782
        g_object_set_property (G_OBJECT (self->priv->agent->agent),
Packit 133782
            g_param_spec_get_name (pspec), value);
Packit 133782
      break;
Packit 133782
    case PROP_ICE_TCP:
Packit 133782
      self->priv->ice_tcp = g_value_get_boolean (value);
Packit 133782
      if (self->priv->transmitter && self->priv->agent)
Packit 133782
        g_object_set_property (G_OBJECT (self->priv->agent->agent),
Packit 133782
            g_param_spec_get_name (pspec), value);
Packit 133782
      break;
Packit 133782
    case PROP_RELIABLE:
Packit 133782
      self->priv->reliable = g_value_get_boolean (value);
Packit 133782
      break;
Packit 133782
    case PROP_COMPATIBILITY_MODE:
Packit 133782
      self->priv->compatibility_mode = g_value_get_uint (value);
Packit 133782
      break;
Packit 133782
    case PROP_ASSOCIATE_ON_SOURCE:
Packit 133782
      g_atomic_int_set (&self->priv->associate_on_source,
Packit 133782
          g_value_get_boolean (value));
Packit 133782
      break;
Packit 133782
    case PROP_RELAY_INFO:
Packit 133782
      self->priv->relay_info = g_value_dup_boxed (value);
Packit 133782
      break;
Packit 133782
    case PROP_MIN_PORT:
Packit 133782
      self->priv->min_port = g_value_get_uint (value);
Packit 133782
      break;
Packit 133782
    case PROP_MAX_PORT:
Packit 133782
      self->priv->max_port = g_value_get_uint (value);
Packit 133782
      break;
Packit 133782
    case PROP_DEBUG:
Packit 133782
      if (g_value_get_boolean (value)) {
Packit 133782
        nice_debug_enable (TRUE);
Packit 133782
      } else {
Packit 133782
        nice_debug_disable (TRUE);
Packit 133782
      }
Packit 133782
      break;
Packit 133782
    case PROP_SEND_COMPONENT_MUX:
Packit 133782
      self->priv->send_component_mux = g_value_get_boolean (value);
Packit 133782
      if (self->priv->gststream != NULL)
Packit 133782
        fs_nice_transmitter_set_send_component_mux (self->priv->transmitter,
Packit 133782
            self->priv->gststream, self->priv->send_component_mux);
Packit 133782
      break;
Packit 133782
Packit 133782
    default:
Packit 133782
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 133782
      break;
Packit 133782
  }
Packit 133782
}
Packit 133782
Packit 133782
Packit 133782
static NiceCandidateType
Packit 133782
fs_candidate_type_to_nice_candidate_type (FsCandidateType type)
Packit 133782
{
Packit 133782
  switch (type)
Packit 133782
  {
Packit 133782
    case FS_CANDIDATE_TYPE_HOST:
Packit 133782
      return NICE_CANDIDATE_TYPE_HOST;
Packit 133782
    case FS_CANDIDATE_TYPE_SRFLX:
Packit 133782
      return NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE;
Packit 133782
    case FS_CANDIDATE_TYPE_PRFLX:
Packit 133782
      return NICE_CANDIDATE_TYPE_PEER_REFLEXIVE;
Packit 133782
    case FS_CANDIDATE_TYPE_RELAY:
Packit 133782
      return NICE_CANDIDATE_TYPE_RELAYED;
Packit 133782
    default:
Packit 133782
      GST_WARNING ("Invalid candidate type %d, defaulting to type host", type);
Packit 133782
      return NICE_CANDIDATE_TYPE_HOST;
Packit 133782
  }
Packit 133782
}
Packit 133782
Packit 133782
static NiceCandidateTransport
Packit 133782
fs_network_protocol_to_nice_candidate_protocol (FsNetworkProtocol proto)
Packit 133782
{
Packit 133782
  switch (proto)
Packit 133782
  {
Packit 133782
    case FS_NETWORK_PROTOCOL_UDP:
Packit 133782
      return NICE_CANDIDATE_TRANSPORT_UDP;
Packit 133782
    case FS_NETWORK_PROTOCOL_TCP_ACTIVE:
Packit 133782
      return NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
Packit 133782
    case FS_NETWORK_PROTOCOL_TCP_PASSIVE:
Packit 133782
      return NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
Packit 133782
    case FS_NETWORK_PROTOCOL_TCP_SO:
Packit 133782
      return NICE_CANDIDATE_TRANSPORT_TCP_SO;
Packit 133782
    default:
Packit 133782
      GST_WARNING ("Invalid Fs network protocol type %u", proto);
Packit 133782
      return NICE_CANDIDATE_TRANSPORT_UDP;
Packit 133782
  }
Packit 133782
}
Packit 133782
Packit 133782
static NiceCandidate *
Packit 133782
fs_candidate_to_nice_candidate (FsNiceStreamTransmitter *self,
Packit 133782
    FsCandidate *candidate)
Packit 133782
{
Packit 133782
  NiceCandidate *nc = nice_candidate_new (
Packit 133782
      fs_candidate_type_to_nice_candidate_type (candidate->type));
Packit 133782
Packit 133782
  nc->transport =
Packit 133782
    fs_network_protocol_to_nice_candidate_protocol (candidate->proto);
Packit 133782
  nc->priority = candidate->priority;
Packit 133782
  nc->stream_id = self->priv->stream_id;
Packit 133782
  nc->component_id = candidate->component_id;
Packit 133782
  if (candidate->foundation != NULL)
Packit 133782
    strncpy (nc->foundation, candidate->foundation,
Packit 133782
       NICE_CANDIDATE_MAX_FOUNDATION - 1);
Packit 133782
Packit 133782
  nc->username = g_strdup(candidate->username);
Packit 133782
  nc->password = g_strdup(candidate->password);
Packit 133782
Packit 133782
Packit 133782
  if (candidate->ip == NULL)
Packit 133782
    goto error;
Packit 133782
  if (!nice_address_set_from_string (&nc->addr, candidate->ip))
Packit 133782
    goto error;
Packit 133782
  nice_address_set_port (&nc->addr, candidate->port);
Packit 133782
Packit 133782
  if (candidate->base_ip && candidate->base_port)
Packit 133782
  {
Packit 133782
    if (!nice_address_set_from_string (&nc->base_addr, candidate->base_ip))
Packit 133782
      goto error;
Packit 133782
    nice_address_set_port (&nc->base_addr, candidate->base_port);
Packit 133782
  }
Packit 133782
Packit 133782
  return nc;
Packit 133782
Packit 133782
 error:
Packit 133782
  nice_candidate_free (nc);
Packit 133782
  return NULL;
Packit 133782
}
Packit 133782
Packit 133782
Packit 133782
static gboolean
Packit 133782
fs_nice_stream_transmitter_add_remote_candidates (
Packit 133782
    FsStreamTransmitter *streamtransmitter,
Packit 133782
    GList *candidates,
Packit 133782
    GError **error)
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *self =
Packit 133782
    FS_NICE_STREAM_TRANSMITTER (streamtransmitter);
Packit 133782
  GList  *item;
Packit 133782
  GSList *nice_candidates = NULL;
Packit 133782
  gint c;
Packit 133782
  const gchar *username;
Packit 133782
  const gchar *password;
Packit 133782
Packit 133782
  if (!candidates)
Packit 133782
  {
Packit 133782
    GST_DEBUG ("NULL candidates passed, lets do an ICE restart");
Packit 133782
    FS_NICE_STREAM_TRANSMITTER_LOCK (self);
Packit 133782
    if (self->priv->remote_candidates)
Packit 133782
      fs_candidate_list_destroy (self->priv->remote_candidates);
Packit 133782
    self->priv->remote_candidates = NULL;
Packit 133782
    self->priv->forced_candidates = FALSE;
Packit 133782
    g_free (self->priv->username);
Packit 133782
    g_free (self->priv->password);
Packit 133782
    self->priv->username = NULL;
Packit 133782
    self->priv->password = NULL;
Packit 133782
    FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
    nice_agent_restart (self->priv->agent->agent);
Packit 133782
    return TRUE;
Packit 133782
  }
Packit 133782
Packit 133782
  FS_NICE_STREAM_TRANSMITTER_LOCK (self);
Packit 133782
Packit 133782
  username = self->priv->username;
Packit 133782
  password = self->priv->password;
Packit 133782
Packit 133782
  /* Validate candidates */
Packit 133782
  for (item = candidates;
Packit 133782
       item;
Packit 133782
       item = g_list_next (item))
Packit 133782
  {
Packit 133782
    FsCandidate *candidate = item->data;
Packit 133782
Packit 133782
    if (!candidate->ip)
Packit 133782
    {
Packit 133782
      FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
          "Candidate MUST have an IP address");
Packit 133782
      return FALSE;
Packit 133782
    }
Packit 133782
Packit 133782
    if (candidate->component_id == 0 ||
Packit 133782
        candidate->component_id > self->priv->transmitter->components)
Packit 133782
    {
Packit 133782
      FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
          "Candidate MUST have a component id between 1 and %d, %d is invalid",
Packit 133782
          self->priv->transmitter->components, candidate->component_id);
Packit 133782
      return FALSE;
Packit 133782
    }
Packit 133782
Packit 133782
    if (candidate->type == FS_CANDIDATE_TYPE_MULTICAST)
Packit 133782
    {
Packit 133782
      FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
          "libnice transmitter does not accept multicast candidates");
Packit 133782
      return FALSE;
Packit 133782
    }
Packit 133782
Packit 133782
    if (!candidate->username)
Packit 133782
    {
Packit 133782
      FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
          "Invalid remote candidates passed, does not have a username");
Packit 133782
      return FALSE;
Packit 133782
    }
Packit 133782
Packit 133782
    if (self->priv->compatibility_mode != NICE_COMPATIBILITY_GOOGLE &&
Packit 133782
        !candidate->password)
Packit 133782
    {
Packit 133782
      FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
          "Invalid remote candidates passed, does not have a password");
Packit 133782
      return FALSE;
Packit 133782
    }
Packit 133782
Packit 133782
    if (self->priv->compatibility_mode != NICE_COMPATIBILITY_GOOGLE &&
Packit 133782
        self->priv->compatibility_mode != NICE_COMPATIBILITY_MSN &&
Packit 133782
        self->priv->compatibility_mode != NICE_COMPATIBILITY_OC2007)
Packit 133782
    {
Packit 133782
      if (!username)
Packit 133782
      {
Packit 133782
        username = candidate->username;
Packit 133782
      }
Packit 133782
      else if (strcmp (username, candidate->username))
Packit 133782
      {
Packit 133782
        FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
        g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
            "Invalid remote candidates passed, does not have the right"
Packit 133782
            " username");
Packit 133782
        return FALSE;
Packit 133782
      }
Packit 133782
Packit 133782
      if (!password)
Packit 133782
      {
Packit 133782
        password = candidate->password;
Packit 133782
      }
Packit 133782
      else if (strcmp (password, candidate->password))
Packit 133782
      {
Packit 133782
        FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
        g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
            "Invalid remote candidates passed, does not have the right"
Packit 133782
            " password");
Packit 133782
        return FALSE;
Packit 133782
      }
Packit 133782
    }
Packit 133782
  }
Packit 133782
Packit 133782
  if (!self->priv->username)
Packit 133782
    self->priv->username = g_strdup (username);
Packit 133782
  if (!self->priv->password)
Packit 133782
    self->priv->password = g_strdup (password);
Packit 133782
Packit 133782
  if (self->priv->forced_candidates)
Packit 133782
  {
Packit 133782
    FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
    g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
        "Candidates have been forced, can't set remote candidates");
Packit 133782
    return FALSE;
Packit 133782
  }
Packit 133782
Packit 133782
  if (!self->priv->gathered)
Packit 133782
  {
Packit 133782
    self->priv->remote_candidates = g_list_concat (
Packit 133782
        self->priv->remote_candidates,
Packit 133782
        fs_candidate_list_copy (candidates));
Packit 133782
    FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
    return TRUE;
Packit 133782
  }
Packit 133782
Packit 133782
  if (self->priv->compatibility_mode != NICE_COMPATIBILITY_GOOGLE &&
Packit 133782
      self->priv->compatibility_mode != NICE_COMPATIBILITY_MSN &&
Packit 133782
      self->priv->compatibility_mode != NICE_COMPATIBILITY_OC2007)
Packit 133782
  {
Packit 133782
    username = g_strdup (username);
Packit 133782
    password = g_strdup (password);
Packit 133782
    FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
Packit 133782
    if (!nice_agent_set_remote_credentials (self->priv->agent->agent,
Packit 133782
            self->priv->stream_id, username, password))
Packit 133782
    {
Packit 133782
      g_free ((gchar*) username);
Packit 133782
      g_free ((gchar*) password);
Packit 133782
      g_set_error (error, FS_ERROR, FS_ERROR_INTERNAL,
Packit 133782
          "Could not set the security credentials");
Packit 133782
      return FALSE;
Packit 133782
    }
Packit 133782
    g_free ((gchar*) username);
Packit 133782
    g_free ((gchar*) password);
Packit 133782
  }
Packit 133782
  else
Packit 133782
  {
Packit 133782
    FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
  }
Packit 133782
Packit 133782
  for (c = 1; c <= self->priv->transmitter->components; c++)
Packit 133782
  {
Packit 133782
    for (item = candidates;
Packit 133782
         item;
Packit 133782
         item = g_list_next (item))
Packit 133782
    {
Packit 133782
      FsCandidate *candidate = item->data;
Packit 133782
Packit 133782
      if (candidate->component_id == c)
Packit 133782
      {
Packit 133782
        NiceCandidate *nc = fs_candidate_to_nice_candidate (self, candidate);
Packit 133782
Packit 133782
        if (!nc)
Packit 133782
          goto error;
Packit 133782
Packit 133782
        nice_candidates = g_slist_append (nice_candidates, nc);
Packit 133782
      }
Packit 133782
    }
Packit 133782
Packit 133782
    nice_agent_set_remote_candidates (self->priv->agent->agent,
Packit 133782
        self->priv->stream_id, c, nice_candidates);
Packit 133782
Packit 133782
    g_slist_foreach (nice_candidates, (GFunc)nice_candidate_free, NULL);
Packit 133782
    g_slist_free (nice_candidates);
Packit 133782
    nice_candidates = NULL;
Packit 133782
  }
Packit 133782
Packit 133782
  return TRUE;
Packit 133782
 error:
Packit 133782
Packit 133782
  g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
      "Invalid remote candidates passed");
Packit 133782
  g_slist_foreach (nice_candidates, (GFunc) nice_candidate_free, NULL);
Packit 133782
  g_slist_free (nice_candidates);
Packit 133782
Packit 133782
  return FALSE;
Packit 133782
}
Packit 133782
Packit 133782
static gboolean
Packit 133782
fs_nice_stream_transmitter_force_remote_candidates_act (
Packit 133782
    FsNiceStreamTransmitter *self,
Packit 133782
    GList *remote_candidates)
Packit 133782
{
Packit 133782
  gboolean res = TRUE;
Packit 133782
  GList *item = NULL;
Packit 133782
Packit 133782
  for (item = remote_candidates;
Packit 133782
       item && res;
Packit 133782
       item = g_list_next (item))
Packit 133782
  {
Packit 133782
    FsCandidate *candidate = item->data;
Packit 133782
    NiceCandidate *nc = fs_candidate_to_nice_candidate (self, candidate);
Packit 133782
Packit 133782
    res &= nice_agent_set_selected_remote_candidate (self->priv->agent->agent,
Packit 133782
        self->priv->stream_id, candidate->component_id, nc);
Packit 133782
    nice_candidate_free (nc);
Packit 133782
  }
Packit 133782
Packit 133782
  return res;
Packit 133782
}
Packit 133782
Packit 133782
static gboolean
Packit 133782
fs_nice_stream_transmitter_force_remote_candidates (
Packit 133782
    FsStreamTransmitter *streamtransmitter,
Packit 133782
    GList *remote_candidates,
Packit 133782
    GError **error)
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *self =
Packit 133782
    FS_NICE_STREAM_TRANSMITTER (streamtransmitter);
Packit 133782
  GList *item = NULL;
Packit 133782
  gboolean res = TRUE;
Packit 133782
  gboolean *done;
Packit 133782
Packit 133782
  done = g_new0(gboolean, self->priv->transmitter->components);
Packit 133782
Packit 133782
  memset (done, 0, self->priv->transmitter->components * sizeof (gboolean));
Packit 133782
Packit 133782
  if (self->priv->stream_id == 0)
Packit 133782
  {
Packit 133782
    g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
        "Can not call this function before gathering local candidates");
Packit 133782
    res = FALSE;
Packit 133782
    goto out;
Packit 133782
  }
Packit 133782
Packit 133782
  /* First lets check that we have valid candidates */
Packit 133782
Packit 133782
  for (item = remote_candidates; item; item = g_list_next (item))
Packit 133782
  {
Packit 133782
    FsCandidate *candidate = item->data;
Packit 133782
Packit 133782
    if (candidate->component_id < 1 ||
Packit 133782
        candidate->component_id > self->priv->transmitter->components)
Packit 133782
    {
Packit 133782
      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
          "The component on this candidate is wrong");
Packit 133782
      res = FALSE;
Packit 133782
      goto out;
Packit 133782
    }
Packit 133782
Packit 133782
    if (done[candidate->component_id-1])
Packit 133782
    {
Packit 133782
      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
          "You can set only one candidate per component");
Packit 133782
      res = FALSE;
Packit 133782
      goto out;
Packit 133782
    }
Packit 133782
    done[candidate->component_id-1] = TRUE;
Packit 133782
  }
Packit 133782
Packit 133782
  FS_NICE_STREAM_TRANSMITTER_LOCK (self);
Packit 133782
  self->priv->forced_candidates = TRUE;
Packit 133782
  if (self->priv->gathered)
Packit 133782
  {
Packit 133782
    FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
    res = fs_nice_stream_transmitter_force_remote_candidates_act (self,
Packit 133782
        remote_candidates);
Packit 133782
  }
Packit 133782
  else
Packit 133782
  {
Packit 133782
    if (self->priv->remote_candidates)
Packit 133782
      fs_candidate_list_destroy (self->priv->remote_candidates);
Packit 133782
    self->priv->remote_candidates = fs_candidate_list_copy (remote_candidates);
Packit 133782
    FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
  }
Packit 133782
Packit 133782
  if (!res)
Packit 133782
    g_set_error (error, FS_ERROR, FS_ERROR_INTERNAL,
Packit 133782
        "Unknown error while selecting remote candidates");
Packit 133782
Packit 133782
out:
Packit 133782
  g_free(done);
Packit 133782
  return res;
Packit 133782
}
Packit 133782
Packit 133782
static FsCandidateType
Packit 133782
nice_candidate_type_to_fs_candidate_type (NiceCandidateType type)
Packit 133782
{
Packit 133782
  switch (type)
Packit 133782
  {
Packit 133782
    case NICE_CANDIDATE_TYPE_HOST:
Packit 133782
      return FS_CANDIDATE_TYPE_HOST;
Packit 133782
    case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
Packit 133782
      return FS_CANDIDATE_TYPE_SRFLX;
Packit 133782
    case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
Packit 133782
      return FS_CANDIDATE_TYPE_PRFLX;
Packit 133782
    case NICE_CANDIDATE_TYPE_RELAYED:
Packit 133782
      return FS_CANDIDATE_TYPE_RELAY;
Packit 133782
    default:
Packit 133782
      GST_WARNING ("Invalid candidate type %d, defaulting to type host", type);
Packit 133782
      return FS_CANDIDATE_TYPE_HOST;
Packit 133782
  }
Packit 133782
}
Packit 133782
Packit 133782
static FsNetworkProtocol
Packit 133782
nice_candidate_transport_to_fs_network_protocol (NiceCandidateTransport trans)
Packit 133782
{
Packit 133782
  switch (trans)
Packit 133782
  {
Packit 133782
    case NICE_CANDIDATE_TRANSPORT_UDP:
Packit 133782
      return FS_NETWORK_PROTOCOL_UDP;
Packit 133782
    case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
Packit 133782
      return FS_NETWORK_PROTOCOL_TCP_PASSIVE;
Packit 133782
    case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
Packit 133782
      return FS_NETWORK_PROTOCOL_TCP_ACTIVE;
Packit 133782
    case NICE_CANDIDATE_TRANSPORT_TCP_SO:
Packit 133782
      return FS_NETWORK_PROTOCOL_TCP_SO;
Packit 133782
    default:
Packit 133782
      GST_WARNING ("Invalid Nice network transport type %u", trans);
Packit 133782
      return FS_NETWORK_PROTOCOL_UDP;
Packit 133782
  }
Packit 133782
}
Packit 133782
Packit 133782
static FsCandidate *
Packit 133782
nice_candidate_to_fs_candidate (NiceAgent *agent, NiceCandidate *nicecandidate,
Packit 133782
    gboolean local)
Packit 133782
{
Packit 133782
  FsCandidate *fscandidate;
Packit 133782
  gchar *ipaddr = g_malloc (INET6_ADDRSTRLEN);
Packit 133782
Packit 133782
  nice_address_to_string (&nicecandidate->addr, ipaddr);
Packit 133782
Packit 133782
  fscandidate = fs_candidate_new (
Packit 133782
      nicecandidate->foundation,
Packit 133782
      nicecandidate->component_id,
Packit 133782
      nice_candidate_type_to_fs_candidate_type (nicecandidate->type),
Packit 133782
      nice_candidate_transport_to_fs_network_protocol (
Packit 133782
          nicecandidate->transport),
Packit 133782
      ipaddr,
Packit 133782
      nice_address_get_port (&nicecandidate->addr));
Packit 133782
Packit 133782
  if (nice_address_is_valid (&nicecandidate->base_addr) &&
Packit 133782
      nicecandidate->type != NICE_CANDIDATE_TYPE_HOST)
Packit 133782
  {
Packit 133782
    nice_address_to_string (&nicecandidate->base_addr, ipaddr);
Packit 133782
    fscandidate->base_ip = ipaddr;
Packit 133782
    fscandidate->base_port = nice_address_get_port (&nicecandidate->base_addr);
Packit 133782
  }
Packit 133782
  else
Packit 133782
  {
Packit 133782
    g_free (ipaddr);
Packit 133782
    ipaddr = NULL;
Packit 133782
  }
Packit 133782
Packit 133782
  fscandidate->username = g_strdup (nicecandidate->username);
Packit 133782
  fscandidate->password = g_strdup (nicecandidate->password);
Packit 133782
  fscandidate->priority = nicecandidate->priority;
Packit 133782
Packit 133782
  if (local && fscandidate->username == NULL && fscandidate->password == NULL)
Packit 133782
  {
Packit 133782
    gchar *username = NULL, *password = NULL;
Packit 133782
    nice_agent_get_local_credentials (agent, nicecandidate->stream_id,
Packit 133782
        &username, &password);
Packit 133782
    fscandidate->username = username;
Packit 133782
    fscandidate->password = password;
Packit 133782
Packit 133782
    if (username == NULL || password == NULL)
Packit 133782
    {
Packit 133782
      GST_WARNING ("The stream has no credentials??");
Packit 133782
    }
Packit 133782
  }
Packit 133782
Packit 133782
Packit 133782
Packit 133782
  return fscandidate;
Packit 133782
}
Packit 133782
Packit 133782
Packit 133782
static gboolean
Packit 133782
candidate_list_are_equal (GList *list1, GList *list2)
Packit 133782
{
Packit 133782
  for (;
Packit 133782
       list1 && list2;
Packit 133782
       list1 = list1->next, list2 = list2->next)
Packit 133782
  {
Packit 133782
    FsCandidate *cand1 = list1->data;
Packit 133782
    FsCandidate *cand2 = list2->data;
Packit 133782
Packit 133782
    if (strcmp (cand1->ip, cand2->ip))
Packit 133782
        return FALSE;
Packit 133782
  }
Packit 133782
Packit 133782
  return TRUE;
Packit 133782
}
Packit 133782
Packit 133782
static void
Packit 133782
weak_agent_removed (gpointer user_data, GObject *where_the_object_was)
Packit 133782
{
Packit 133782
  GList *agents = NULL;
Packit 133782
  FsParticipant *participant = user_data;
Packit 133782
Packit 133782
  FS_PARTICIPANT_DATA_LOCK (participant);
Packit 133782
Packit 133782
  agents = g_object_get_data (G_OBJECT (participant), "nice-agents");
Packit 133782
  agents = g_list_remove (agents, where_the_object_was);
Packit 133782
  g_object_set_data (G_OBJECT (participant), "nice-agents", agents);
Packit 133782
Packit 133782
  FS_PARTICIPANT_DATA_UNLOCK (participant);
Packit 133782
Packit 133782
  g_object_unref (participant);
Packit 133782
}
Packit 133782
Packit 133782
static gboolean
Packit 133782
fs_nice_stream_transmitter_set_relay_info (FsNiceStreamTransmitter *self,
Packit 133782
    const GstStructure *s, guint component_id, GError **error)
Packit 133782
{
Packit 133782
  const gchar *username, *password, *ip;
Packit 133782
  const gchar *relay_type_string;
Packit 133782
  NiceRelayType relay_type = NICE_RELAY_TYPE_TURN_UDP;
Packit 133782
  guint port;
Packit 133782
  gboolean has_port;
Packit 133782
Packit 133782
  ip = gst_structure_get_string (s, "ip");
Packit 133782
  has_port = gst_structure_get_uint (s, "port",  &port);
Packit 133782
  username = gst_structure_get_string (s, "username");
Packit 133782
  password = gst_structure_get_string (s, "password");
Packit 133782
  relay_type_string = gst_structure_get_string (s, "relay-type");
Packit 133782
Packit 133782
  if (!ip || !has_port || !username || !password || port > 65535)
Packit 133782
  {
Packit 133782
    g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
        "Need to pass an ip, port, username and password for a relay");
Packit 133782
    return FALSE;
Packit 133782
  }
Packit 133782
Packit 133782
  if (relay_type_string)
Packit 133782
  {
Packit 133782
    if (!g_ascii_strcasecmp(relay_type_string, "tcp"))
Packit 133782
      relay_type = NICE_RELAY_TYPE_TURN_TCP;
Packit 133782
    else if (!g_ascii_strcasecmp(relay_type_string, "tls"))
Packit 133782
      relay_type = NICE_RELAY_TYPE_TURN_TLS;
Packit 133782
  }
Packit 133782
Packit 133782
  nice_agent_set_relay_info(self->priv->agent->agent,
Packit 133782
      self->priv->stream_id, component_id, ip, port, username, password,
Packit 133782
      relay_type);
Packit 133782
Packit 133782
  return TRUE;
Packit 133782
}
Packit 133782
Packit 133782
Packit 133782
Packit 133782
static void
Packit 133782
tos_changed (GObject *transmitter, GParamSpec *param,
Packit 133782
    FsNiceStreamTransmitter *self)
Packit 133782
{
Packit 133782
  guint tos;
Packit 133782
Packit 133782
  g_object_get (transmitter, "tos", &tos, NULL);
Packit 133782
  nice_agent_set_stream_tos (self->priv->agent->agent, self->priv->stream_id,
Packit 133782
      tos);
Packit 133782
}
Packit 133782
Packit 133782
static gboolean
Packit 133782
fs_nice_stream_transmitter_build (FsNiceStreamTransmitter *self,
Packit 133782
    FsParticipant *participant,
Packit 133782
    GError **error)
Packit 133782
{
Packit 133782
  GList *item;
Packit 133782
  GList *agents  = NULL;
Packit 133782
  FsNiceAgent *agent = NULL;
Packit 133782
  gint i;
Packit 133782
Packit 133782
  /* Before going any further, check that the list of candidates are ok */
Packit 133782
Packit 133782
  for (item = g_list_first (self->priv->preferred_local_candidates);
Packit 133782
       item;
Packit 133782
       item = g_list_next (item))
Packit 133782
  {
Packit 133782
    FsCandidate *cand = item->data;
Packit 133782
Packit 133782
    if (cand->ip == NULL)
Packit 133782
    {
Packit 133782
      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
          "You have to set an ip on your preferred candidate");
Packit 133782
      return FALSE;
Packit 133782
    }
Packit 133782
Packit 133782
    if (cand->port || cand->component_id)
Packit 133782
    {
Packit 133782
      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
          "You can not set a port or component id"
Packit 133782
          " for the preferred nice candidate");
Packit 133782
      return FALSE;
Packit 133782
    }
Packit 133782
Packit 133782
    if (cand->type != FS_CANDIDATE_TYPE_HOST)
Packit 133782
    {
Packit 133782
      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
          "You can only set preferred candidates of type host");
Packit 133782
      return FALSE;
Packit 133782
    }
Packit 133782
  }
Packit 133782
Packit 133782
  /* Now if we have a relayinfo, lets verify that its ok */
Packit 133782
Packit 133782
  if (self->priv->relay_info)
Packit 133782
  {
Packit 133782
    for (i = 0; i < self->priv->relay_info->len; i++)
Packit 133782
    {
Packit 133782
      const GstStructure *s = g_ptr_array_index (self->priv->relay_info, i);
Packit 133782
Packit 133782
      if (!s)
Packit 133782
      {
Packit 133782
        g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
            "Element %d of the relay-info GPtrArray is NULL",
Packit 133782
            i);
Packit 133782
        return FALSE;
Packit 133782
      }
Packit 133782
Packit 133782
      if (!gst_structure_has_field_typed (s, "ip", G_TYPE_STRING))
Packit 133782
      {
Packit 133782
        g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
            "Element %d of the relay-info does not have an ip as a string", i);
Packit 133782
        return FALSE;
Packit 133782
      }
Packit 133782
Packit 133782
      if (!gst_structure_has_field_typed (s, "port", G_TYPE_UINT))
Packit 133782
      {
Packit 133782
        g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
            "Element %d of the relay-info does not have a port as a guint", i);
Packit 133782
        return FALSE;
Packit 133782
      }
Packit 133782
Packit 133782
      if (gst_structure_has_field (s, "username") &&
Packit 133782
          !gst_structure_has_field_typed (s, "username", G_TYPE_STRING))
Packit 133782
      {
Packit 133782
        g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
            "Element %d of the relay-info has a username that is not a string",
Packit 133782
            i);
Packit 133782
        return FALSE;
Packit 133782
      }
Packit 133782
Packit 133782
      if (gst_structure_has_field (s, "password") &&
Packit 133782
          !gst_structure_has_field_typed (s, "password", G_TYPE_STRING))
Packit 133782
      {
Packit 133782
        g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
            "Element %d of the relay-info has a password that is not a string",
Packit 133782
            i);
Packit 133782
        return FALSE;
Packit 133782
      }
Packit 133782
Packit 133782
      if (gst_structure_has_field (s, "relay-type") &&
Packit 133782
          !gst_structure_has_field_typed (s, "relay-type",
Packit 133782
              G_TYPE_STRING))
Packit 133782
      {
Packit 133782
        g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
            "Element %d of the relay-info a relay-type"
Packit 133782
            " that is not a string", i);
Packit 133782
        return FALSE;
Packit 133782
      }
Packit 133782
Packit 133782
      if (gst_structure_has_field (s, "component") &&
Packit 133782
          !gst_structure_has_field_typed (s, "component",
Packit 133782
              G_TYPE_UINT))
Packit 133782
      {
Packit 133782
        g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
            "Element %d of the relay-info has a component that is not a uint",
Packit 133782
            i);
Packit 133782
        return FALSE;
Packit 133782
      }
Packit 133782
    }
Packit 133782
  }
Packit 133782
Packit 133782
Packit 133782
  /* First find if there is already a matching agent */
Packit 133782
Packit 133782
  FS_PARTICIPANT_DATA_LOCK (participant);
Packit 133782
Packit 133782
  agents = g_object_get_data (G_OBJECT (participant), "nice-agents");
Packit 133782
Packit 133782
  for (item = g_list_first (agents);
Packit 133782
       item;
Packit 133782
       item = g_list_next (item))
Packit 133782
  {
Packit 133782
    guint stun_port;
Packit 133782
    gchar *stun_server;
Packit 133782
    guint compatibility;
Packit 133782
Packit 133782
    agent = item->data;
Packit 133782
Packit 133782
    g_object_get (agent->agent,
Packit 133782
        "stun-server", &stun_server,
Packit 133782
        "stun-server-port", &stun_port,
Packit 133782
        "compatibility", &compatibility,
Packit 133782
        NULL);
Packit 133782
Packit 133782
    /*
Packit 133782
     * Check if the agent matches our requested criteria
Packit 133782
     */
Packit 133782
    if (compatibility == self->priv->compatibility_mode &&
Packit 133782
        stun_port == self->priv->stun_port &&
Packit 133782
        (stun_server == self->priv->stun_ip ||
Packit 133782
            (stun_server && self->priv->stun_ip &&
Packit 133782
                !strcmp (stun_server, self->priv->stun_ip))))
Packit 133782
    {
Packit 133782
      GList *prefs = NULL;
Packit 133782
Packit 133782
      g_object_get (G_OBJECT (agent),
Packit 133782
          "preferred-local-candidates", &prefs,
Packit 133782
          NULL);
Packit 133782
Packit 133782
      if (candidate_list_are_equal (prefs,
Packit 133782
              self->priv->preferred_local_candidates))
Packit 133782
      {
Packit 133782
        fs_candidate_list_destroy (prefs);
Packit 133782
        break;
Packit 133782
      }
Packit 133782
      fs_candidate_list_destroy (prefs);
Packit 133782
    }
Packit 133782
  }
Packit 133782
Packit 133782
Packit 133782
  /* In this case we need to build a new agent */
Packit 133782
  if (item == NULL)
Packit 133782
  {
Packit 133782
    agent = fs_nice_agent_new (self->priv->compatibility_mode,
Packit 133782
        self->priv->preferred_local_candidates, self->priv->reliable,
Packit 133782
        error);
Packit 133782
Packit 133782
    if (!agent)
Packit 133782
        return FALSE;
Packit 133782
Packit 133782
    if (self->priv->stun_ip && self->priv->stun_port)
Packit 133782
      g_object_set (agent->agent,
Packit 133782
          "stun-server", self->priv->stun_ip,
Packit 133782
          "stun-server-port", self->priv->stun_port,
Packit 133782
          NULL);
Packit 133782
Packit 133782
    g_object_set (agent->agent,
Packit 133782
        "controlling-mode", self->priv->controlling_mode,
Packit 133782
        "ice-udp", self->priv->ice_udp,
Packit 133782
        "ice-tcp", self->priv->ice_tcp,
Packit 133782
        NULL);
Packit 133782
Packit 133782
    agents = g_list_prepend (agents, agent);
Packit 133782
    g_object_set_data (G_OBJECT (participant), "nice-agents", agents);
Packit 133782
    g_object_weak_ref (G_OBJECT (agent), weak_agent_removed, participant);
Packit 133782
    g_object_ref (participant);
Packit 133782
Packit 133782
    self->priv->agent = agent;
Packit 133782
  } else {
Packit 133782
    self->priv->agent = g_object_ref (agent);
Packit 133782
  }
Packit 133782
Packit 133782
  FS_PARTICIPANT_DATA_UNLOCK (participant);
Packit 133782
Packit 133782
  self->priv->component_has_been_ready = g_new0 (gboolean,
Packit 133782
      self->priv->transmitter->components);
Packit 133782
Packit 133782
  self->priv->stream_id = nice_agent_add_stream (
Packit 133782
      self->priv->agent->agent,
Packit 133782
      self->priv->transmitter->components);
Packit 133782
Packit 133782
  if (self->priv->stream_id == 0)
Packit 133782
  {
Packit 133782
    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
Packit 133782
        "Could not create libnice stream");
Packit 133782
    return FALSE;
Packit 133782
  }
Packit 133782
Packit 133782
  /* if we have a relay- info, lets set it */
Packit 133782
  if (self->priv->relay_info)
Packit 133782
  {
Packit 133782
    gint c;
Packit 133782
    for (c = 1; c <= self->priv->transmitter->components; c++)
Packit 133782
    {
Packit 133782
      gboolean relay_info_set = FALSE;
Packit 133782
Packit 133782
      for (i = 0; i < self->priv->relay_info->len; i++)
Packit 133782
      {
Packit 133782
        const GstStructure *s = g_ptr_array_index (self->priv->relay_info, i);
Packit 133782
        guint component_id;
Packit 133782
Packit 133782
        if (gst_structure_get_uint (s, "component", &component_id) &&
Packit 133782
            component_id == c)
Packit 133782
        {
Packit 133782
          if (!fs_nice_stream_transmitter_set_relay_info (self, s, c, error))
Packit 133782
            return FALSE;
Packit 133782
          relay_info_set = TRUE;
Packit 133782
        }
Packit 133782
      }
Packit 133782
Packit 133782
      if (!relay_info_set)
Packit 133782
      {
Packit 133782
        for (i = 0; i < self->priv->relay_info->len; i++)
Packit 133782
        {
Packit 133782
          const GstStructure *s = g_ptr_array_index (self->priv->relay_info, i);
Packit 133782
Packit 133782
          if (!gst_structure_has_field (s, "component"))
Packit 133782
            if (!fs_nice_stream_transmitter_set_relay_info (self, s, c, error))
Packit 133782
              return FALSE;
Packit 133782
        }
Packit 133782
      }
Packit 133782
    }
Packit 133782
  }
Packit 133782
Packit 133782
  /* Set a port range if it has been specified. */
Packit 133782
  if (self->priv->min_port && (self->priv->min_port < self->priv->max_port))
Packit 133782
  {
Packit 133782
    gint c;
Packit 133782
    for (c = 1; c <= self->priv->transmitter->components; c++)
Packit 133782
    {
Packit 133782
      nice_agent_set_port_range (self->priv->agent->agent,
Packit 133782
          self->priv->stream_id, c, self->priv->min_port, self->priv->max_port);
Packit 133782
    }
Packit 133782
  }
Packit 133782
Packit 133782
  self->priv->state_changed_handler_id = g_signal_connect_object (agent->agent,
Packit 133782
      "component-state-changed", G_CALLBACK (agent_state_changed), self, 0);
Packit 133782
  self->priv->gathering_done_handler_id = g_signal_connect_object (agent->agent,
Packit 133782
      "candidate-gathering-done", G_CALLBACK (agent_gathering_done), self, 0);
Packit 133782
  self->priv->new_selected_pair_handler_id = g_signal_connect_object (
Packit 133782
      agent->agent, "new-selected-pair", G_CALLBACK (agent_new_selected_pair),
Packit 133782
      self, 0);
Packit 133782
  self->priv->new_candidate_handler_id = g_signal_connect_object (agent->agent,
Packit 133782
      "new-candidate", G_CALLBACK (agent_new_candidate), self, 0);
Packit 133782
  self->priv->tos_changed_handler_id = g_signal_connect_object (
Packit 133782
      self->priv->transmitter, "notify::tos", G_CALLBACK (tos_changed), self,
Packit 133782
      0);
Packit 133782
Packit 133782
  tos_changed (G_OBJECT (self->priv->transmitter), NULL, self);
Packit 133782
Packit 133782
  self->priv->gststream = fs_nice_transmitter_add_gst_stream (
Packit 133782
      self->priv->transmitter,
Packit 133782
      self->priv->agent->agent,
Packit 133782
      self->priv->stream_id,
Packit 133782
      known_buffer_have_buffer_handler, self,
Packit 133782
      error);
Packit 133782
  if (self->priv->gststream == NULL)
Packit 133782
    return FALSE;
Packit 133782
Packit 133782
  fs_nice_transmitter_set_send_component_mux (self->priv->transmitter,
Packit 133782
      self->priv->gststream, self->priv->send_component_mux);
Packit 133782
Packit 133782
  GST_DEBUG ("Created a stream with %u components",
Packit 133782
      self->priv->transmitter->components);
Packit 133782
Packit 133782
  return TRUE;
Packit 133782
}
Packit 133782
Packit 133782
static gboolean
Packit 133782
fs_nice_stream_transmitter_gather_local_candidates (
Packit 133782
    FsStreamTransmitter *streamtransmitter,
Packit 133782
    GError **error)
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *self =
Packit 133782
    FS_NICE_STREAM_TRANSMITTER (streamtransmitter);
Packit 133782
Packit 133782
  GST_DEBUG ("Stream %u started", self->priv->stream_id);
Packit 133782
Packit 133782
  nice_agent_gather_candidates (self->priv->agent->agent,
Packit 133782
      self->priv->stream_id);
Packit 133782
Packit 133782
  return TRUE;
Packit 133782
}
Packit 133782
Packit 133782
static FsStreamState
Packit 133782
nice_component_state_to_fs_stream_state (NiceComponentState state)
Packit 133782
{
Packit 133782
  switch (state)
Packit 133782
  {
Packit 133782
    case NICE_COMPONENT_STATE_DISCONNECTED:
Packit 133782
      return FS_STREAM_STATE_DISCONNECTED;
Packit 133782
    case NICE_COMPONENT_STATE_GATHERING:
Packit 133782
      return FS_STREAM_STATE_GATHERING;
Packit 133782
    case NICE_COMPONENT_STATE_CONNECTING:
Packit 133782
      return FS_STREAM_STATE_CONNECTING;
Packit 133782
    case NICE_COMPONENT_STATE_CONNECTED:
Packit 133782
      return FS_STREAM_STATE_CONNECTED;
Packit 133782
    case NICE_COMPONENT_STATE_READY:
Packit 133782
      return FS_STREAM_STATE_READY;
Packit 133782
    case NICE_COMPONENT_STATE_FAILED:
Packit 133782
      return FS_STREAM_STATE_FAILED;
Packit 133782
    default:
Packit 133782
      GST_ERROR ("Invalid state %u", state);
Packit 133782
      return FS_STREAM_STATE_FAILED;
Packit 133782
  }
Packit 133782
}
Packit 133782
Packit 133782
struct state_changed_signal_data
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *self;
Packit 133782
  guint component_id;
Packit 133782
  FsStreamState fs_state;
Packit 133782
};
Packit 133782
Packit 133782
static void
Packit 133782
free_state_changed_signal_data (gpointer user_data)
Packit 133782
{
Packit 133782
  struct state_changed_signal_data *data = user_data;
Packit 133782
  g_object_unref (data->self);
Packit 133782
  g_slice_free (struct state_changed_signal_data, data);
Packit 133782
}
Packit 133782
Packit 133782
static gboolean
Packit 133782
state_changed_signal_idle (gpointer userdata)
Packit 133782
{
Packit 133782
  struct state_changed_signal_data *data = userdata;
Packit 133782
Packit 133782
  g_signal_emit_by_name (data->self, "state-changed", data->component_id,
Packit 133782
      data->fs_state);
Packit 133782
  return FALSE;
Packit 133782
}
Packit 133782
Packit 133782
static void
Packit 133782
agent_state_changed (NiceAgent *agent,
Packit 133782
    guint stream_id,
Packit 133782
    guint component_id,
Packit 133782
    guint state,
Packit 133782
    gpointer user_data)
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (user_data);
Packit 133782
  FsStreamState fs_state;
Packit 133782
  struct state_changed_signal_data *data;
Packit 133782
Packit 133782
  if (stream_id != self->priv->stream_id)
Packit 133782
    return;
Packit 133782
Packit 133782
  g_return_if_fail (component_id > 0 &&
Packit 133782
      component_id <= self->priv->transmitter->components);
Packit 133782
Packit 133782
  /* Ignore failed until we've connected, never time out because
Packit 133782
   * of the dribbling case, more candidates could come later
Packit 133782
   */
Packit 133782
  if (state == NICE_COMPONENT_STATE_FAILED &&
Packit 133782
      !self->priv->component_has_been_ready[component_id - 1])
Packit 133782
    return;
Packit 133782
  else if (state == NICE_COMPONENT_STATE_READY)
Packit 133782
    self->priv->component_has_been_ready[component_id - 1] = TRUE;
Packit 133782
Packit 133782
  fs_state = nice_component_state_to_fs_stream_state (state);
Packit 133782
  data = g_slice_new (struct state_changed_signal_data);
Packit 133782
Packit 133782
  GST_DEBUG ("Stream: %u Component %u has state %u",
Packit 133782
      self->priv->stream_id, component_id, state);
Packit 133782
Packit 133782
  data->self = g_object_ref (self);
Packit 133782
  data->component_id = component_id;
Packit 133782
  data->fs_state = fs_state;
Packit 133782
  fs_nice_agent_add_idle (self->priv->agent, state_changed_signal_idle,
Packit 133782
      data, free_state_changed_signal_data);
Packit 133782
Packit 133782
  if (fs_state >= FS_STREAM_STATE_CONNECTED)
Packit 133782
  {
Packit 133782
    FS_NICE_STREAM_TRANSMITTER_LOCK (self);
Packit 133782
    if (self->priv->gststream)
Packit 133782
      fs_nice_transmitter_request_keyunit (self->priv->transmitter,
Packit 133782
          self->priv->gststream, component_id);
Packit 133782
    FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
  }
Packit 133782
}
Packit 133782
Packit 133782
Packit 133782
struct candidate_signal_data
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *self;
Packit 133782
  const gchar *signal_name;
Packit 133782
  FsCandidate *candidate1;
Packit 133782
  FsCandidate *candidate2;
Packit 133782
};
Packit 133782
Packit 133782
static void
Packit 133782
free_candidate_signal_data (gpointer user_data)
Packit 133782
{
Packit 133782
  struct candidate_signal_data *data = user_data;
Packit 133782
  fs_candidate_destroy (data->candidate1);
Packit 133782
  if (data->candidate2)
Packit 133782
    fs_candidate_destroy (data->candidate2);
Packit 133782
  g_object_unref (data->self);
Packit 133782
  g_slice_free (struct candidate_signal_data, data);
Packit 133782
}
Packit 133782
Packit 133782
static gboolean
Packit 133782
agent_candidate_signal_idle (gpointer userdata)
Packit 133782
{
Packit 133782
  struct candidate_signal_data *data = userdata;
Packit 133782
Packit 133782
  g_signal_emit_by_name (data->self, data->signal_name, data->candidate1,
Packit 133782
                         data->candidate2);
Packit 133782
  return FALSE;
Packit 133782
}
Packit 133782
Packit 133782
Packit 133782
static void
Packit 133782
agent_new_selected_pair (NiceAgent *agent,
Packit 133782
    guint stream_id,
Packit 133782
    guint component_id,
Packit 133782
    const gchar *lfoundation,
Packit 133782
    const gchar *rfoundation,
Packit 133782
    gpointer user_data)
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (user_data);
Packit 133782
  GSList *candidates, *item;
Packit 133782
  FsCandidate *local = NULL;
Packit 133782
  FsCandidate *remote = NULL;
Packit 133782
Packit 133782
  if (stream_id != self->priv->stream_id)
Packit 133782
    return;
Packit 133782
Packit 133782
  candidates = nice_agent_get_local_candidates (agent,
Packit 133782
      self->priv->stream_id, component_id);
Packit 133782
Packit 133782
  for (item = candidates; item; item = g_slist_next (item))
Packit 133782
  {
Packit 133782
    NiceCandidate *candidate = item->data;
Packit 133782
Packit 133782
    if (!strcmp (candidate->foundation, lfoundation))
Packit 133782
    {
Packit 133782
      local = nice_candidate_to_fs_candidate (agent, candidate, TRUE);
Packit 133782
      break;
Packit 133782
    }
Packit 133782
  }
Packit 133782
  g_slist_foreach (candidates, (GFunc)nice_candidate_free, NULL);
Packit 133782
  g_slist_free (candidates);
Packit 133782
Packit 133782
  candidates = nice_agent_get_remote_candidates (agent,
Packit 133782
      self->priv->stream_id, component_id);
Packit 133782
Packit 133782
  for (item = candidates; item; item = g_slist_next (item))
Packit 133782
  {
Packit 133782
    NiceCandidate *candidate = item->data;
Packit 133782
Packit 133782
    if (!strcmp (candidate->foundation, rfoundation))
Packit 133782
    {
Packit 133782
      remote = nice_candidate_to_fs_candidate (agent, candidate, FALSE);
Packit 133782
      break;
Packit 133782
    }
Packit 133782
  }
Packit 133782
  g_slist_foreach (candidates, (GFunc)nice_candidate_free, NULL);
Packit 133782
  g_slist_free (candidates);
Packit 133782
Packit 133782
Packit 133782
  if (local && remote)
Packit 133782
  {
Packit 133782
    struct candidate_signal_data *data =
Packit 133782
      g_slice_new (struct candidate_signal_data);
Packit 133782
    data->self = g_object_ref (self);
Packit 133782
    data->signal_name = "new-active-candidate-pair";
Packit 133782
    data->candidate1 = local;
Packit 133782
    data->candidate2 = remote;
Packit 133782
    fs_nice_agent_add_idle (self->priv->agent, agent_candidate_signal_idle,
Packit 133782
        data, free_candidate_signal_data);
Packit 133782
  }
Packit 133782
  else
Packit 133782
  {
Packit 133782
    if (local)
Packit 133782
      fs_candidate_destroy (local);
Packit 133782
    if (remote)
Packit 133782
      fs_candidate_destroy (remote);
Packit 133782
  }
Packit 133782
}
Packit 133782
Packit 133782
static void
Packit 133782
agent_new_candidate (NiceAgent *agent,
Packit 133782
    guint stream_id,
Packit 133782
    guint component_id,
Packit 133782
    const gchar *foundation,
Packit 133782
    gpointer user_data)
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (user_data);
Packit 133782
  FsCandidate *fscandidate = NULL;
Packit 133782
  GSList *candidates, *item;
Packit 133782
Packit 133782
  if (stream_id != self->priv->stream_id)
Packit 133782
    return;
Packit 133782
Packit 133782
  GST_DEBUG ("New candidate found for stream %u component %u",
Packit 133782
      stream_id, component_id);
Packit 133782
Packit 133782
  candidates = nice_agent_get_local_candidates (agent, stream_id, component_id);
Packit 133782
Packit 133782
  for (item = candidates; item; item = g_slist_next (item))
Packit 133782
  {
Packit 133782
    NiceCandidate *candidate = item->data;
Packit 133782
Packit 133782
    if (!strcmp (candidate->foundation, foundation))
Packit 133782
    {
Packit 133782
      fscandidate = nice_candidate_to_fs_candidate (agent, candidate, TRUE);
Packit 133782
      break;
Packit 133782
    }
Packit 133782
  }
Packit 133782
  g_slist_foreach (candidates, (GFunc) nice_candidate_free, NULL);
Packit 133782
  g_slist_free (candidates);
Packit 133782
Packit 133782
  if (fscandidate)
Packit 133782
  {
Packit 133782
    FS_NICE_STREAM_TRANSMITTER_LOCK (self);
Packit 133782
    if (!self->priv->gathered)
Packit 133782
    {
Packit 133782
      /* Nice doesn't do connchecks while gathering, so don't tell the upper
Packit 133782
       * layers about the candidates untill gathering is finished.
Packit 133782
       * Also older versions of farstream would fail the connection right away
Packit 133782
       * when the first candidate given failed immediately (e.g. ipv6 on a
Packit 133782
       * non-ipv6 capable host, so we order ipv6 candidates after ipv4 ones */
Packit 133782
Packit 133782
       if (strchr (fscandidate->ip, ':'))
Packit 133782
        self->priv->local_candidates = g_list_append
Packit 133782
          (self->priv->local_candidates, fscandidate);
Packit 133782
      else
Packit 133782
        self->priv->local_candidates = g_list_prepend
Packit 133782
          (self->priv->local_candidates, fscandidate);
Packit 133782
      FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
    }
Packit 133782
    else
Packit 133782
    {
Packit 133782
      struct candidate_signal_data *data =
Packit 133782
        g_slice_new (struct candidate_signal_data);
Packit 133782
Packit 133782
      FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
Packit 133782
      data->self = g_object_ref (self);
Packit 133782
      data->signal_name = "new-local-candidate";
Packit 133782
      data->candidate1 = fscandidate;
Packit 133782
      data->candidate2 = NULL;
Packit 133782
      fs_nice_agent_add_idle (self->priv->agent, agent_candidate_signal_idle,
Packit 133782
        data, free_candidate_signal_data);
Packit 133782
    }
Packit 133782
  }
Packit 133782
  else
Packit 133782
  {
Packit 133782
    GST_WARNING ("Could not find local candidate with foundation %s"
Packit 133782
        " for component %d in stream %d", foundation, component_id,
Packit 133782
        stream_id);
Packit 133782
  }
Packit 133782
}
Packit 133782
Packit 133782
Packit 133782
static gboolean
Packit 133782
agent_gathering_done_idle (gpointer data)
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *self = data;
Packit 133782
  GList *remote_candidates = NULL;
Packit 133782
  GList *local_candidates = NULL;
Packit 133782
  gboolean forced_candidates;
Packit 133782
Packit 133782
  FS_NICE_STREAM_TRANSMITTER_LOCK (self);
Packit 133782
  if (self->priv->gathered)
Packit 133782
  {
Packit 133782
    FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
    return FALSE;
Packit 133782
  }
Packit 133782
Packit 133782
  self->priv->gathered = TRUE;
Packit 133782
  remote_candidates = self->priv->remote_candidates;
Packit 133782
  self->priv->remote_candidates = NULL;
Packit 133782
  local_candidates = self->priv->local_candidates;
Packit 133782
  self->priv->local_candidates = NULL;
Packit 133782
  forced_candidates = self->priv->forced_candidates;
Packit 133782
  FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
Packit 133782
Packit 133782
  GST_DEBUG ("Candidates gathered for stream %u", self->priv->stream_id);
Packit 133782
Packit 133782
  if (local_candidates)
Packit 133782
  {
Packit 133782
    GList *l;
Packit 133782
Packit 133782
    for (l = local_candidates ; l != NULL; l = g_list_next (l))
Packit 133782
      g_signal_emit_by_name (self, "new-local-candidate", l->data);
Packit 133782
    fs_candidate_list_destroy (local_candidates);
Packit 133782
  }
Packit 133782
Packit 133782
  g_signal_emit_by_name (self, "local-candidates-prepared");
Packit 133782
Packit 133782
  if (remote_candidates)
Packit 133782
  {
Packit 133782
    if (forced_candidates)
Packit 133782
    {
Packit 133782
      if (!fs_nice_stream_transmitter_force_remote_candidates_act (self,
Packit 133782
              remote_candidates))
Packit 133782
      {
Packit 133782
        fs_stream_transmitter_emit_error (FS_STREAM_TRANSMITTER (self),
Packit 133782
            FS_ERROR_INTERNAL,
Packit 133782
            "Error setting delayed forced remote candidates");
Packit 133782
      }
Packit 133782
    }
Packit 133782
    else
Packit 133782
    {
Packit 133782
      GError *error = NULL;
Packit 133782
Packit 133782
      if (self->priv->compatibility_mode != NICE_COMPATIBILITY_GOOGLE &&
Packit 133782
          self->priv->compatibility_mode != NICE_COMPATIBILITY_MSN &&
Packit 133782
          self->priv->compatibility_mode != NICE_COMPATIBILITY_OC2007)
Packit 133782
      {
Packit 133782
        if (!nice_agent_set_remote_credentials (self->priv->agent->agent,
Packit 133782
                self->priv->stream_id, self->priv->username,
Packit 133782
                self->priv->password))
Packit 133782
        {
Packit 133782
          fs_stream_transmitter_emit_error (FS_STREAM_TRANSMITTER (self),
Packit 133782
              FS_ERROR_INTERNAL,
Packit 133782
              "Could not set the security credentials");
Packit 133782
          fs_candidate_list_destroy (remote_candidates);
Packit 133782
          return FALSE;
Packit 133782
        }
Packit 133782
      }
Packit 133782
Packit 133782
Packit 133782
      if (!fs_nice_stream_transmitter_add_remote_candidates (
Packit 133782
              FS_STREAM_TRANSMITTER_CAST (self),
Packit 133782
              remote_candidates, &error))
Packit 133782
      {
Packit 133782
        fs_stream_transmitter_emit_error (FS_STREAM_TRANSMITTER (self),
Packit 133782
            error->code, error->message);
Packit 133782
      }
Packit 133782
      g_clear_error (&error);
Packit 133782
    }
Packit 133782
Packit 133782
    fs_candidate_list_destroy (remote_candidates);
Packit 133782
  }
Packit 133782
Packit 133782
  return FALSE;
Packit 133782
}
Packit 133782
Packit 133782
Packit 133782
static void
Packit 133782
agent_gathering_done (NiceAgent *agent, guint stream_id, gpointer user_data)
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (user_data);
Packit 133782
Packit 133782
  if (stream_id != self->priv->stream_id)
Packit 133782
    return;
Packit 133782
Packit 133782
  fs_nice_agent_add_idle (self->priv->agent, agent_gathering_done_idle,
Packit 133782
      g_object_ref (self), g_object_unref);
Packit 133782
}
Packit 133782
Packit 133782
Packit 133782
FsNiceStreamTransmitter *
Packit 133782
fs_nice_stream_transmitter_newv (FsNiceTransmitter *transmitter,
Packit 133782
    FsParticipant *participant,
Packit 133782
    guint n_parameters,
Packit 133782
    GParameter *parameters,
Packit 133782
    GError **error)
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *streamtransmitter = NULL;
Packit 133782
Packit 133782
  if (!participant || !FS_IS_PARTICIPANT (participant))
Packit 133782
  {
Packit 133782
    g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
Packit 133782
        "You need a valid participant");
Packit 133782
    return NULL;
Packit 133782
  }
Packit 133782
Packit 133782
  streamtransmitter = g_object_newv (FS_TYPE_NICE_STREAM_TRANSMITTER,
Packit 133782
    n_parameters, parameters);
Packit 133782
Packit 133782
  if (!streamtransmitter)
Packit 133782
  {
Packit 133782
    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
Packit 133782
      "Could not build the stream transmitter");
Packit 133782
    return NULL;
Packit 133782
  }
Packit 133782
Packit 133782
  streamtransmitter->priv->transmitter = g_object_ref (transmitter);
Packit 133782
Packit 133782
  if (!fs_nice_stream_transmitter_build (streamtransmitter, participant, error))
Packit 133782
  {
Packit 133782
    g_object_unref (streamtransmitter);
Packit 133782
    return NULL;
Packit 133782
  }
Packit 133782
Packit 133782
  return streamtransmitter;
Packit 133782
}
Packit 133782
Packit 133782
Packit 133782
static GstPadProbeReturn
Packit 133782
known_buffer_have_buffer_handler (GstPad *pad, GstPadProbeInfo *info,
Packit 133782
    gpointer user_data)
Packit 133782
{
Packit 133782
  FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (user_data);
Packit 133782
  guint component_id;
Packit 133782
  GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
Packit 133782
Packit 133782
  if (!g_atomic_int_get (&self->priv->associate_on_source))
Packit 133782
    return GST_PAD_PROBE_OK;
Packit 133782
Packit 133782
  component_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (pad),
Packit 133782
          "component-id"));
Packit 133782
Packit 133782
  g_signal_emit_by_name (self, "known-source-packet-received", component_id,
Packit 133782
      buffer);
Packit 133782
Packit 133782
  return GST_PAD_PROBE_OK;
Packit 133782
}