Logo Search packages:      
Sourcecode: farsight version File versions  Download package

lj-transmitter.c

/*
 * lj-transmitter.c - Source for libjingle transmitter implementation
 *
 * Farsight Voice+Video library
 * Copyright (C) 2007 Collabora Ltd.
 * Copyright (C) 2007 Nokia Corporation
 *   @author Philippe Kalaf <philippe.kalaf@collabora.co.uk>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "lj-transmitter.h"

#include "farsight-transport.h"

#include "helpers/farsight-interfaces.h"
#include <arpa/inet.h>

#include "jingle_c.h"

#include <gst/gst.h>

#define DEFAULT_STUN_IP "stun.l.google.com"
#define DEFAULT_STUN_PORT 19302

enum
{
  PROP_0,
  PROP_STUN_IP,
  PROP_STUN_PORT,
  PROP_RELAY_TOKEN,
};

struct _FarsightLJTransmitterPrivate
{
  gboolean disposed;

  gboolean prepared;

  GstElement *gst_src;
  GstElement *gst_sink;

  socketclient_t socket_client;

  gchar *stun_ip;
  guint stun_port;

  gchar *relay_token;
};

#define FARSIGHT_LJ_TRANSMITTER_GET_PRIVATE(o)  \
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), FARSIGHT_TYPE_LJ_TRANSMITTER, \
                                FarsightLJTransmitterPrivate))

static void farsight_lj_transmitter_class_init (FarsightLJTransmitterClass *klass);
static void farsight_lj_transmitter_init (FarsightLJTransmitter *lj_transmitter);

static void farsight_lj_transmitter_dispose (GObject *object);
static void farsight_lj_transmitter_finalize (GObject *object);

static gboolean
farsight_lj_transmitter_prepare (FarsightTransmitter *transmitter);

static gboolean
farsight_lj_transmitter_stop (FarsightTransmitter *transmitter);

static void
farsight_lj_transmitter_add_remote_candidates (FarsightTransmitter *transmitter,
    const GList *remote_candidate_list);

static void
farsight_lj_transmitter_create_source (FarsightLJTransmitter *self);
static void
farsight_lj_transmitter_configure_source (FarsightLJTransmitter *self);
static void
farsight_lj_transmitter_create_sink (FarsightLJTransmitter *self);
static void
farsight_lj_transmitter_configure_sink (FarsightLJTransmitter *self);

static void
farsight_lj_transmitter_set_property (GObject * object,
    guint prop_id, const GValue * value, GParamSpec * pspec);

static void
farsight_lj_transmitter_get_property (GObject * object,
    guint prop_id, GValue * value, GParamSpec * pspec);

static void
farsight_lj_transmitter_native_candidate_ready (gpointer user_data,
    const FarsightTransportInfo *candidate);
static void 
farsight_lj_transmitter_socket_state_changed (gpointer user_data, gint state);
static void
farsight_lj_transmitter_network_error (gpointer user_data);

static GstElement*
farsight_lj_transmitter_get_gst_src (FarsightTransmitter *transmitter);

static GstElement*
farsight_lj_transmitter_get_gst_sink (FarsightTransmitter *transmitter);

FarsightTransmitterClass *lj_transmitter_parent_class = NULL;

static GType type = 0;

void
farsight_lj_transmitter_register_type (GTypeModule *module)
{
  static const GTypeInfo info = {
    sizeof (FarsightLJTransmitterClass),
    NULL,
    NULL,
    (GClassInitFunc) farsight_lj_transmitter_class_init,
    NULL,
    NULL,
    sizeof (FarsightLJTransmitter),
    0,
    (GInstanceInitFunc) farsight_lj_transmitter_init
  };

  type = g_type_module_register_type (module, FARSIGHT_TYPE_TRANSMITTER,
      "FarsightLJTransmitter", &info, 0);
}

GType
farsight_lj_transmitter_get_type (void)
{
  return type;
}

static void
farsight_lj_transmitter_class_init (FarsightLJTransmitterClass *klass)
{
  GObjectClass *gobject_class;
  FarsightTransmitterClass *farsight_transmitter_class;

  gobject_class = (GObjectClass *) klass;
  farsight_transmitter_class = (FarsightTransmitterClass *) klass;
  lj_transmitter_parent_class = g_type_class_peek_parent (klass);

  gobject_class->set_property = farsight_lj_transmitter_set_property;
  gobject_class->get_property = farsight_lj_transmitter_get_property;

  g_object_class_install_property (gobject_class, PROP_STUN_IP,
      g_param_spec_string ("stun_ip", "STUN server ip",
        "The IP address of the STUN server to use",
        NULL, G_PARAM_READWRITE));

  g_object_class_install_property (gobject_class, PROP_STUN_PORT,
      g_param_spec_uint ("stun_port", "STUN server port",
        "The port to the STUN server", 0, G_MAXUINT, 0, G_PARAM_READWRITE));

  g_object_class_install_property (gobject_class, PROP_RELAY_TOKEN,
      g_param_spec_string ("relay-token", "Relay token",
        "Relay token", NULL, G_PARAM_READWRITE));

  gobject_class->dispose = farsight_lj_transmitter_dispose;
  gobject_class->finalize = farsight_lj_transmitter_finalize;

  farsight_transmitter_class->prepare = farsight_lj_transmitter_prepare;
  farsight_transmitter_class->stop = farsight_lj_transmitter_stop;
  farsight_transmitter_class->add_remote_candidates =
    farsight_lj_transmitter_add_remote_candidates;
  farsight_transmitter_class->get_gst_src =
    farsight_lj_transmitter_get_gst_src;
  farsight_transmitter_class->get_gst_sink =
    farsight_lj_transmitter_get_gst_sink;

  g_type_class_add_private (klass, sizeof (FarsightLJTransmitterPrivate));
}

static void
farsight_lj_transmitter_init (FarsightLJTransmitter *self)
{
  self->priv = FARSIGHT_LJ_TRANSMITTER_GET_PRIVATE (self);

  self->priv->stun_ip = g_strdup (DEFAULT_STUN_IP);
  self->priv->stun_port = DEFAULT_STUN_PORT;
  self->priv->relay_token = NULL;
}

static gboolean
farsight_lj_transmitter_prepare (FarsightTransmitter *transmitter)
{
  FarsightLJTransmitter *self = FARSIGHT_LJ_TRANSMITTER (transmitter);
  if (self->priv->prepared)
    return FALSE;

  g_message ("Init and running jinglep2p to prepare native candiates, using stun %s : %d", 
      self->priv->stun_ip, self->priv->stun_port);
  self->priv->socket_client = socketclient_init(self->priv->stun_ip,
          self->priv->stun_port, self->priv->relay_token);

  connect_signal_candidates_ready (self->priv->socket_client,
          farsight_lj_transmitter_native_candidate_ready, transmitter);
  connect_signal_socket_state_change (self->priv->socket_client,
          farsight_lj_transmitter_socket_state_changed, transmitter);
  connect_signal_network_error (self->priv->socket_client,
          farsight_lj_transmitter_network_error, transmitter);

  socketclient_create_socket (self->priv->socket_client, "rtp");

  socketclient_start_processing_candidates (self->priv->socket_client);

  farsight_transmitter_signal_connection_state_changed (transmitter,
      FARSIGHT_TRANSMITTER_STATE_CONNECTING);

  if (self->priv->gst_src)
  {
    farsight_lj_transmitter_configure_source (self);
  }
  else
  {
    farsight_lj_transmitter_create_source (self);
  }

  if (self->priv->gst_sink)
  {
    farsight_lj_transmitter_configure_sink (self);
  }
  else
  {
    farsight_lj_transmitter_create_sink (self);
  }

  return TRUE;
}

static gboolean
farsight_lj_transmitter_stop (FarsightTransmitter *transmitter)
{
  FarsightLJTransmitter *self = FARSIGHT_LJ_TRANSMITTER (transmitter);

  if (self->priv->socket_client)
  {
    g_debug ("%s (%d): destroying socket client", __FUNCTION__, __LINE__);
    socketclient_destroy (self->priv->socket_client);
    self->priv->socket_client = NULL;
  }

  return TRUE;
}

static void
farsight_lj_transmitter_add_remote_candidates (FarsightTransmitter *transmitter,
    const GList *remote_candidate_list)
{
  FarsightLJTransmitter *self = FARSIGHT_LJ_TRANSMITTER (transmitter);
  if (self->priv->socket_client)
  {
    socketclient_add_remote_candidates(self->priv->socket_client,
        remote_candidate_list);
  }
  else
  {
    g_warning ("Could not set remote candidates because the transmitter has"
        " not been prepared");
  }
}

static GstElement*
farsight_lj_transmitter_get_gst_src (FarsightTransmitter *transmitter)
{
  FarsightLJTransmitter *self = FARSIGHT_LJ_TRANSMITTER (transmitter);
  if (!self->priv->gst_src)
  {
    farsight_lj_transmitter_create_source (self);
  }
  return self->priv->gst_src;
}

static GstElement*
farsight_lj_transmitter_get_gst_sink (FarsightTransmitter *transmitter)
{
  FarsightLJTransmitter *self = FARSIGHT_LJ_TRANSMITTER (transmitter);
  if (!self->priv->gst_sink)
  {
    farsight_lj_transmitter_create_sink (self);
  }
  return self->priv->gst_sink;
}

static void
farsight_lj_transmitter_dispose (GObject *object)
{
  FarsightLJTransmitter *self = FARSIGHT_LJ_TRANSMITTER (object);

  if (self->priv->disposed) {
    /* If dispose did already run, return. */
    return;
  }

  self->priv->disposed = TRUE;

  /* chain up to parent */
  G_OBJECT_CLASS (lj_transmitter_parent_class)->dispose (object);
}

static void
farsight_lj_transmitter_finalize (GObject *object)
{
  FarsightLJTransmitter *self = FARSIGHT_LJ_TRANSMITTER (object);

  g_return_if_fail (self != NULL);
  g_return_if_fail (FARSIGHT_IS_LJ_TRANSMITTER (self));

  G_OBJECT_CLASS (lj_transmitter_parent_class)->finalize (object);
}

static void
farsight_lj_transmitter_create_source (FarsightLJTransmitter *self)
{
  self->priv->gst_src =
    gst_element_factory_make ("icesrc", "icesrc");

  if (self->priv->gst_src == NULL)
  {
    g_warning ("Could not add icesrc!");
    return;
  }

  farsight_lj_transmitter_configure_source (self);
}

static void
farsight_lj_transmitter_configure_source (FarsightLJTransmitter *self)
{
  if (self->priv->socket_client)
  {
    g_object_set (G_OBJECT(self->priv->gst_src), "socketclient",
        self->priv->socket_client, NULL);
  }
}

static void
farsight_lj_transmitter_create_sink (FarsightLJTransmitter *self)
{
  self->priv->gst_sink =
    gst_element_factory_make ("icesink", "icesink");

  if (self->priv->gst_sink == NULL)
  {
    g_warning ("Could not add icesink!");
    return;
  }

  farsight_lj_transmitter_configure_sink (self);
}

static void
farsight_lj_transmitter_configure_sink (FarsightLJTransmitter *self)
{
  if (self->priv->socket_client)
  {
    g_object_set (G_OBJECT(self->priv->gst_sink), "socketclient",
        self->priv->socket_client, NULL);
  }
}

static void
farsight_lj_transmitter_set_property (GObject * object,
    guint prop_id, const GValue * value, GParamSpec * pspec)
{
  FarsightLJTransmitter *self = FARSIGHT_LJ_TRANSMITTER (object);

  switch (prop_id) {
    case PROP_STUN_IP:
      self->priv->stun_ip = g_value_dup_string (value);
      break;
    case PROP_STUN_PORT:
      self->priv->stun_port = g_value_get_uint (value);
      break;
    case PROP_RELAY_TOKEN:
      self->priv->relay_token = g_value_dup_string (value);
      g_debug ("%s: setting relay token to %s", G_STRFUNC, self->priv->relay_token);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
farsight_lj_transmitter_get_property (GObject * object,
    guint prop_id, GValue * value, GParamSpec * pspec)
{
  FarsightLJTransmitter *self = FARSIGHT_LJ_TRANSMITTER (object);

  switch (prop_id) {
    case PROP_STUN_IP:
      g_value_set_string (value, self->priv->stun_ip);
      break;
    case PROP_STUN_PORT:
      g_value_set_uint (value, self->priv->stun_port);
      break;
    case PROP_RELAY_TOKEN:
      g_value_set_string (value, self->priv->relay_token);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
farsight_lj_transmitter_native_candidate_ready (gpointer user_data,
    const FarsightTransportInfo *candidate)
{
  FarsightTransmitter *transmitter = FARSIGHT_TRANSMITTER (user_data);
  farsight_transmitter_signal_new_native_candidate (transmitter, candidate);
}

static void 
farsight_lj_transmitter_socket_state_changed (gpointer user_data, gint state)
{
  FarsightTransmitter *transmitter = FARSIGHT_TRANSMITTER (user_data);

  g_message ("socket state changed to %d", state);

  if (state == 1)     /* writable */
    {
      /* FIXME: dirty hack */
      farsight_transmitter_signal_new_active_candidate_pair
        (transmitter, "foo", "bar");

      farsight_transmitter_signal_connection_state_changed (transmitter,
          FARSIGHT_TRANSMITTER_STATE_CONNECTED);
    }
  else if (state == 0)
    {
      /* What we really want here is some sort of _pause/_resume functionality
       * in farsight */
      farsight_transmitter_signal_connection_state_changed (transmitter,
          FARSIGHT_TRANSMITTER_STATE_CONNECTING);
    }
}

static void
farsight_lj_transmitter_network_error (gpointer user_data)
{
  FarsightTransmitter *transmitter = FARSIGHT_TRANSMITTER (user_data);
  farsight_transmitter_signal_error (transmitter,
      FARSIGHT_TRANSMITTER_ERROR_UNKNOWN,
      "Got an unknown error from libjingle");
}

static GObject *
farsight_lj_transmitter_new (void)
{
  return g_object_new(FARSIGHT_TYPE_LJ_TRANSMITTER, NULL);
}

static gboolean 
init_plugin (FarsightPlugin *plugin)
{
  farsight_lj_transmitter_register_type (G_TYPE_MODULE (plugin));

  return TRUE;
}

static FarsightPluginInfo plugin_info = {
    FARSIGHT_MAJOR_VERSION,
    FARSIGHT_MINOR_VERSION,
    "Libjingle bastard-ICE transmitter",                                /* description */
    "0.1.0",                                            /* version */
    "Farsight Project",  /* author */
    "http://farsight.sf.net/",                          /* homepage */
    NULL,                                               /* unload */
    farsight_lj_transmitter_new,                        /* new */
};

FARSIGHT_INIT_PLUGIN (init_plugin, plugin_info);

Generated by  Doxygen 1.6.0   Back to index