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

farsight-stream.c

/*
 * farsight-stream.c - Source for core API streams
 *
 * Farsight Voice+Video library
 * Copyright 2005,2006 Collabora Ltd.
 * Copyright 2005,2006 Nokia Corp.
 *   @author Rob Taylor <rob.taylor@collabora.co.uk>
 *   @author Philippe Kalaf <philippe.kalaf@collabora.co.uk>
 * Copyright (c) 2005 INdT
 *   @author Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>
 *
 * 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
 */

/**
 * SECTION:farsight-stream
 * @short_description: A object that represents and manages a single
 * real-time audio/video stream.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <libintl.h>
#define _(String) gettext (String)
#define gettext_noop(String) String

#include "farsight-marshal.h"
#include "farsight-session.h"
#include "farsight-stream.h"

/* Signals */
enum
{
  ERROR,
  NEW_NATIVE_CANDIDATE,
  NATIVE_CANDIDATES_PREPARED,
  NEW_ACTIVE_CANDIDATE_PAIR,
  CODEC_CHANGED,
  CHOSE_CANDIDATES,
  STATE_CHANGED,
  SINK_PAD_READY,
  LAST_SIGNAL
};

/* props */
enum
{
  ARG_0,
  ARG_MEDIA_TYPE,
  ARG_DIRECTION
};

struct _FarsightStreamPrivate
{
  FarsightMediaType media_type;
  FarsightStreamState state;
  FarsightStreamDirection direction;
  FarsightStreamDirection current_direction;
  gboolean disposed;
};

#define FARSIGHT_STREAM_GET_PRIVATE(o)  \
   (G_TYPE_INSTANCE_GET_PRIVATE ((o), FARSIGHT_TYPE_STREAM, FarsightStreamPrivate))

static void farsight_stream_class_init (FarsightStreamClass *klass);
static void farsight_stream_init (FarsightStream *self);
static void farsight_stream_dispose (GObject *object);
static void farsight_stream_finalize (GObject *object);

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

static GObjectClass *parent_class = NULL;
static guint signals[LAST_SIGNAL] = { 0 };

GType
farsight_stream_get_type (void)
{
  static GType type = 0;

  if (type == 0) {
    static const GTypeInfo info = {
      sizeof (FarsightStreamClass),
      NULL,
      NULL,
      (GClassInitFunc) farsight_stream_class_init,
      NULL,
      NULL,
      sizeof (FarsightStream),
      0,
      (GInstanceInitFunc) farsight_stream_init
    };

    type = g_type_register_static (G_TYPE_OBJECT,
        "FarsightStream", &info, 0);
  }

  return type;
}

static void
farsight_stream_class_init (FarsightStreamClass *klass)
{
  GObjectClass *gobject_class;

  gobject_class = (GObjectClass *) klass;
  parent_class = g_type_class_peek_parent (klass);

  gobject_class->set_property = farsight_stream_set_property;
  gobject_class->get_property = farsight_stream_get_property;

  /**
   * FarsightStream:media-type:
   *
   * The media type to be used by this stream specifed by #FarsightMediaType.
   *
   */
  g_object_class_install_property (gobject_class,
          ARG_MEDIA_TYPE,
          g_param_spec_uint ("media-type",
              "Farsight Stream Media Type",
              "The media type to use (Specified by #FarsightMediaType)",
              FARSIGHT_MEDIA_TYPE_AUDIO,
              FARSIGHT_MEDIA_TYPE_LAST,
              FARSIGHT_MEDIA_TYPE_AUDIO,
              G_PARAM_CONSTRUCT_ONLY |G_PARAM_READWRITE));

  /* TODO make this a constructor parameter */
  /**
   * FarsightStream:direction:
   *
   * The direction of this stream. This should only be set at stream creation
   * time.
   *
   */
  g_object_class_install_property (gobject_class,
          ARG_DIRECTION,
          g_param_spec_uint ("direction",
              "Farsight Stream Direction",
              "The stream direction (Specified by #FarsightStreamDirection)",
              FARSIGHT_STREAM_DIRECTION_NONE,
              FARSIGHT_STREAM_DIRECTION_LAST,
              FARSIGHT_STREAM_DIRECTION_BOTH,
              G_PARAM_CONSTRUCT_ONLY |G_PARAM_READWRITE));

  /**
   * FarsightStream::error:
   * @self: #FarsightStream that emmitted the signal
   * @type: #FarsightStreamError type of error
   * @message: Error message
   *
   * This signal is emitted in any error condition
   */
  signals[ERROR] = g_signal_new ("error",
      G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST,
      0,
      NULL,
      NULL,
      farsight_marshal_VOID__INT_STRING,
      G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_STRING);

  /**
   * FarsightStream::new-native-candidate:
   * @self: #FarsightStream that emmitted the signal
   * @candidate_id: id of the found candidate
   *
   * This signal is emitted when the a new native candidate is found.  After
   * emission of this signal, #farsight_stream_get_native_candidates
   * should return meaningful data. This does not mean that the candidate has been
   * prepared.
   */
  signals[NEW_NATIVE_CANDIDATE] = g_signal_new ("new-native-candidate",
      G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST,
      0,
      NULL,
      NULL,
      g_cclosure_marshal_VOID__STRING,
      G_TYPE_NONE, 1, G_TYPE_STRING);

  /**
   * FarsightStream::native-candidates-prepared:
   * @self: #FarsightStream that emmitted the signal
   *
   * This signal is emitted when the native candidates have been prepared.  This
   * usually means all of the local ports have been opened, local interfaces have
   * been found, and/or external ports have been found, and/or relay server has
   * been setup, or anything else the protocol needs.  After emission of this
   * signal, #farsight_stream_get_native_candidate_list should return
   * meaningful data
   */
  signals[NATIVE_CANDIDATES_PREPARED] = g_signal_new ("native-candidates-prepared",
      G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST,
      0,
      NULL,
      NULL,
      g_cclosure_marshal_VOID__VOID,
      G_TYPE_NONE, 0);

  /**
   * FarsightStream::new-active-candidate-pair:
   * @self: #FarsightStream that emmitted the signal
   * @native_candidate_id: string identifier for native side of the candidate pair
   * @remote_candidate_id: string identifier for remote side of the candidate pair
   *
   * Emitted when this FarsightStream has chosen a new active candidate pair
   * to use to connect to the remote client. 
   */
  signals[NEW_ACTIVE_CANDIDATE_PAIR] = 
    g_signal_new ("new-active-candidate-pair",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  0,
                  NULL,
                  NULL,
                  farsight_marshal_VOID__STRING_STRING,
                  G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);

  /**
   * FarsightStream::codec-changed:
   * @self: #FarsightStream that emitted the signal
   * @codec_id: id of codec to be used
   *
   * emitted if we automatically choose a new codec for some reason
   * (e.g. high packet loss)
   */
  signals[CODEC_CHANGED] = g_signal_new ("codec-changed",
      G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST,
      0,
      NULL,
      NULL,
      g_cclosure_marshal_VOID__INT,
      G_TYPE_NONE, 1, G_TYPE_INT);

  /**
   * FarsightStream::state-changed:
   * @self: #FarsightStream that emmitted the signal
   * @state: #FarsightStreamState of new state
   * @direction: #FarsightStreamDirection for directions in 
   *         which the stream is streaming
   *
   * This signal is emitted when we change #FarsightStreamState.
   */
  signals[STATE_CHANGED] = g_signal_new ("state-changed",
      G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST,
      0,
      NULL,
      NULL,
      farsight_marshal_VOID__INT_INT,
      G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);

  /**
   * FarsightStream::sink-pad-ready:
   * @self: #FarsightStream that emmitted the signal
   * @pad: A GstPad that represents the sink
   *
   * This signal is emitted when a sink pad has been created on the Farsight
   * stream bin.
   *
   * Note : This signal is only valid when a user-defined pipeline has been
   * provided by the user to farsight using #farsight_stream_set_pipeline.
   */
  signals[SINK_PAD_READY] = g_signal_new ("sink-pad-ready",
      G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST,
      0,
      NULL,
      NULL,
      g_cclosure_marshal_VOID__POINTER,
      G_TYPE_NONE, 1, G_TYPE_POINTER);

  gobject_class->dispose = farsight_stream_dispose;
  gobject_class->finalize = farsight_stream_finalize;

  g_type_class_add_private (klass, sizeof (FarsightStreamPrivate));
}

static void
farsight_stream_init (FarsightStream *self)
{  
  /* member init */
  self->priv = FARSIGHT_STREAM_GET_PRIVATE (self);
  self->priv->disposed = FALSE;
  self->priv->state = FARSIGHT_STREAM_STATE_DISCONNECTED;
  self->priv->direction = FARSIGHT_STREAM_DIRECTION_BOTH;
  self->priv->current_direction = FARSIGHT_STREAM_DIRECTION_NONE;
}

static void
farsight_stream_dispose (GObject *object)
{
  FarsightStream *self = FARSIGHT_STREAM (object);

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

  /* Make sure dispose does not run twice. */
  self->priv->disposed = TRUE;

  parent_class->dispose (object);
}

static void
farsight_stream_finalize (GObject *object)
{
  g_signal_handlers_destroy (object);

  parent_class->finalize (object);
}

/**
 * farsight_stream_prepare_transports:
 * @self: a #FarsightStream
 *
 * Prepare a stream for connection. This function should enumerate local
 * interfaces, open any ports and determine external ip/ports (STUN), start
 * relay server (TURN).
 *
 * It should also set a callback function for taking appropriate action when a
 * new local interface has been detected by connecting to signal
 * #new-native-candiate.
 */
void
farsight_stream_prepare_transports (FarsightStream *self)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (self), FARSIGHT_TYPE_STREAM));

  if (klass->prepare_transports) { 
    klass->prepare_transports (self);
  } else {
    g_warning ("prepare_transports not defined for %s", 
        G_OBJECT_TYPE_NAME (self));
  }
}

/**
 * farsight_stream_get_native_candidate_list:
 * @self: a #FarsightStream
 *
 * Get list of native candidates for this stream
 * Returns: #GList of #FarsightTransportInfo
 */
G_CONST_RETURN GList *
farsight_stream_get_native_candidate_list (FarsightStream *self)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self), 
              FARSIGHT_TYPE_STREAM), NULL);

  if (klass->get_native_candidate_list) {
    return klass->get_native_candidate_list (self);
  } else {
    g_warning ("get_native_candidate_list not defined for %s", 
        G_OBJECT_TYPE_NAME (self));
  }
  return NULL; // this shouldn't happen
}

/**
 * farsight_stream_get_native_candidate:
 * @self: a #FarsightStream
 * @candidate_id: a string indicating the candidate id
 *
 * Returns a specific native candidate
 *
 * Return value: a #GList of #FarsightTransportInfo for the given native
 * candidate. This #GList must be freed using #farsight_transport_list_destroy
 * when not needed anymore.
 */
GList *
farsight_stream_get_native_candidate (FarsightStream *self,
                                      const gchar* candidate_id)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self), 
              FARSIGHT_TYPE_STREAM), NULL);
  g_return_val_if_fail (candidate_id != NULL, NULL);

  if (klass->get_native_candidate) {
    return klass->get_native_candidate (self, candidate_id);
  } else {
    g_warning ("get_native_candidate not defined for %s", 
        G_OBJECT_TYPE_NAME (self));
  }
  return NULL;
}

/**
 * farsight_stream_set_remote_candidate_list:
 * @self: a #FarsightStream
 * @remote_candidates: a #GList of #FarsightTransportInfo
 *
 * Sets a list of remote candidates
 */
void 
farsight_stream_set_remote_candidate_list (FarsightStream *self, 
                                           const GList *remote_candidates)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (self), FARSIGHT_TYPE_STREAM));
  g_return_if_fail (remote_candidates != NULL);

  if (klass->set_remote_candidate_list) {
    klass->set_remote_candidate_list (self, remote_candidates);
  } else {
    g_warning ("set_remote_candidate_list not defined for %s", 
        G_OBJECT_TYPE_NAME (self));
  }
}

/**
 * farsight_stream_add_remote_candidate:
 * @self: a #FarsightStream
 * @remote_candidate: a #GList of #FarsightTransportInfo
 *
 * Adds the given list of transports (forming one candidate) to the list of
 * remote candidates
 */
void 
farsight_stream_add_remote_candidate (FarsightStream *self,
                                      const GList *remote_candidate)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (self), FARSIGHT_TYPE_STREAM));
  g_return_if_fail (remote_candidate != NULL);

  if (klass->add_remote_candidate) {
    klass->add_remote_candidate (self, remote_candidate);
  } else {
    g_warning ("add_remote_candidate not defined for %s", 
        G_OBJECT_TYPE_NAME (self));
  }
}

/**
 * farsight_stream_remove_remote_candidate:
 * @self: a #FarsightStream
 * @remote_candidate_id: a string representing a remote candidate id
 *
 * Removes the given remote candidate from the remote candidate list
 *
 */
void 
farsight_stream_remove_remote_candidate (FarsightStream *self, 
                                         const gchar *remote_candidate_id)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (self), FARSIGHT_TYPE_STREAM));
  g_return_if_fail (remote_candidate_id != NULL);

  if (klass->remove_remote_candidate) {
    klass->remove_remote_candidate (self, remote_candidate_id);
  } else {
    g_warning ("remove_remote_candidate not defined for %s", 
        G_OBJECT_TYPE_NAME (self));
  }
}

/**
 * farsight_stream_set_active_candidate_pair:
 * @self: a #FarsightStream
 * @native_candidate_id: a string representing a native candidate id
 * @remote_candidate_id: a string representing a remote candidate id
 *
 * Sets the given candidate pair as the active candidate pair,
 * and emits the "new-active-candidate-pair" signal.
 *
 * Returns: %TRUE if sucessfully set the active candidate pair
 */
gboolean
farsight_stream_set_active_candidate_pair (FarsightStream *self,
                                           const gchar *native_candidate_id,
                                           const gchar *remote_candidate_id)
{
    FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
    
    g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self), FARSIGHT_TYPE_STREAM), FALSE);
    g_return_val_if_fail (native_candidate_id != NULL, FALSE);
    g_return_val_if_fail (remote_candidate_id != NULL, FALSE);

    if (klass->set_active_candidate_pair) {
        gboolean success;

        success = klass->set_active_candidate_pair(self, native_candidate_id,
            remote_candidate_id);

        if (success)
          {
            farsight_stream_signal_new_active_candidate_pair
              (self, native_candidate_id, remote_candidate_id);
          }

        return success;
    } else {
        g_warning ("set_active_candidate_pair not defined for %s", 
                G_OBJECT_TYPE_NAME (self));
    }
    return FALSE;
}

/**
 * farsight_stream_set_local_codecs:
 * @self: a #FarsightStream
 * @codecs: a #GList containing codec ids as gints as the list members
 *
 * Set the selection of local codec ids to restrict this stream to using 
 */
/*
void
farsight_stream_set_local_codecs (FarsightStream * self,
                                  const GList * codecs)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (self), FARSIGHT_TYPE_STREAM));

  if (klass->set_local_codecs) {
    klass->set_local_codecs (self, codecs);
  } else {
    g_warning ("set_local_codecs not defined for %s", 
        G_OBJECT_TYPE_NAME (self));
  }
}*/

/**
 * farsight_stream_get_local_codecs:
 * @self: a #FarsightStream
 *
 * Get the selection of local codec ids to restrict this stream to using 
 *
 * Returns : a #GList of codec ids
 */
G_CONST_RETURN GList *
farsight_stream_get_local_codecs (FarsightStream *self)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self), 
              FARSIGHT_TYPE_STREAM), NULL);

  if (klass->get_local_codecs) {
    return klass->get_local_codecs (self);
  } else {
    g_warning ("set_local_codecs not defined for %s", 
        G_OBJECT_TYPE_NAME (self));
  }
  return NULL;
}

/**
 * farsight_stream_set_remote_codecs:
 * @self: a #FarsightStream
 * @codecs: #GList of #FarsightCodec 
 *
 * Set the selection of codecs that the remote end claims to understand
 *
 * Return value: %TRUE if it succeeds and %FALSE if there is no intersection
 * between remote and local codecs.
 */
gboolean
farsight_stream_set_remote_codecs (FarsightStream *self,
                                   const GList *codecs)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (FARSIGHT_IS_STREAM(self), FALSE);
  g_return_val_if_fail (codecs != NULL, FALSE);

  if (klass->set_remote_codecs) {
    return klass->set_remote_codecs (self, codecs);
  } else {
    g_warning ("set_remote_codecs not defined for %s",
        G_OBJECT_TYPE_NAME (self));
    return FALSE;
  }
}

/**
 * farsight_stream_get_codec_intersection:
 * @self: a #FarsightStream
 *
 * Get the intersection of local and remote codecs.
 *
 * Returns: a #GList of #FarsightCodec. The caller is responsible
 *          for freeing the list and individual items when
 *          it's done with it.
 */
GList *
farsight_stream_get_codec_intersection (FarsightStream *self)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self),
              FARSIGHT_TYPE_STREAM), NULL);

  if (klass->get_codec_intersection) {
    return klass->get_codec_intersection (self);
  } else {
    g_warning ("get_codec_intersection not defined for %s",
        G_OBJECT_TYPE_NAME (self));
  }
  return NULL;
}

/**
 * farsight_stream_set_codec_preference_list:
 * @self: a #FarsightStream
 * @codec_pref: a GArray of #FarsightCodecPreference
 *
 * Set a list of prefered codecs (optional)
 *
 */
void farsight_stream_set_codec_preference_list (FarsightStream *self,
    const GArray *codec_pref)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (self), FARSIGHT_TYPE_STREAM));

  if (klass->set_codec_preference_list) {
    klass->set_codec_preference_list (self, codec_pref);
  } else {
    g_warning ("set_codec_preference_list not defined for %s",
        G_OBJECT_TYPE_NAME (self));
  }
}

/**
 * farsight_stream_set_active_codec:
 * @self: a #FarsightStream
 * @id: id of codec to use
 *
 * Set the codec to use for this stream. There should now be enough information
 * to build the pipeline.
 */
void
farsight_stream_set_active_codec (FarsightStream *self,
                                  gint id)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (self), FARSIGHT_TYPE_STREAM));

  if (klass->set_active_codec) {
    klass->set_active_codec (self, id);
  } else {
    g_warning ("set_active_codec not defined for %s",
        G_OBJECT_TYPE_NAME (self));
  }
}

/**
 * farsight_stream_get_active_codec:
 * @self: a #FarsightStream
 *
 * Get the codec to use for this stream.
 * Return Value: the id of the codec currently in use, -1 if unset
 */
gint
farsight_stream_get_active_codec (FarsightStream *self)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self),
              FARSIGHT_TYPE_STREAM), -1);

  if (klass->get_active_codec ) {
    return klass->get_active_codec (self);
  } else {
    g_warning ("get_active+codec not defined for %s",
        G_OBJECT_TYPE_NAME (self));
  }
  return -1;
}

/**
 * farsight_stream_set_sink:
 * @self: a #FarsightStream
 * @sink: a GstElement to use as the sink
 *
 * Set the GStreamer sink for this stream. If sink is NULL it will block the
 * incoming stream and remove the old sink. If called with a new sink it will
 * replace the old one. If there is a user specified pipeline, the sink won't be
 * added into the Farsight bin.
 *
 * Returns: %TRUE if sucessful
 */
gboolean
farsight_stream_set_sink (FarsightStream *self,
                          GstElement *sink)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self),
              FARSIGHT_TYPE_STREAM), FALSE);

  if (klass->set_sink ) {
    return klass->set_sink (self, sink);
  } else {
    g_warning ("set_sink not defined for %s",
        G_OBJECT_TYPE_NAME (self));
  }
  return FALSE;
}

/**
 * farsight_stream_set_sink_filter:
 * @self: a #FarsightStream
 * @filter: a #GstCaps to use as a filter
 * 
 * Set the GStreamer sink link filter for this stream
 *
 * Returns: %TRUE if sucessful
 **/
gboolean 
farsight_stream_set_sink_filter (FarsightStream *self, 
                          GstCaps *filter)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self), 
              FARSIGHT_TYPE_STREAM), FALSE);
  g_return_val_if_fail (filter != NULL, FALSE);

  if (klass->set_sink_filter ) {
    return klass->set_sink_filter (self, filter);
  } else {
    g_warning ("set_sink_filter not defined for %s", 
        G_OBJECT_TYPE_NAME (self));
  }
  return FALSE;
}

/**
 * farsight_stream_get_sink:
 * @self: a #FarsightStream
 *
 * Get the GStreamer sink for this stream
 *
 * Returns: A #GstElement for the current stream sink
 **/
GstElement *
farsight_stream_get_sink (FarsightStream *self)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self),
              FARSIGHT_TYPE_STREAM), FALSE);

  if (klass->get_sink ) {
    return klass->get_sink (self);
  } else {
    g_warning ("get_sink not defined for %s",
        G_OBJECT_TYPE_NAME (self));
  }
  return NULL;
}

/**
 * farsight_stream_set_source:
 * @self: a #FarsightStream
 * @source: a GstElement to use as the source
 *
 * Set the GStreamer source for this stream. If the element does not have a
 * parent, it will be added into the Farsight stream bin. So if you need to set
 * a parent for the source, do it before calling this function.
 *
 * Returns: %TRUE if sucessful
 **/
gboolean
farsight_stream_set_source (FarsightStream *self,
                            GstElement *source)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self), FARSIGHT_TYPE_STREAM),
                        FALSE);
  g_return_val_if_fail (source != NULL, FALSE);

  if (klass->set_source) {
    return klass->set_source (self, source);
  } else {
    g_warning ("set_source not defined for %s",
        G_OBJECT_TYPE_NAME (self));
  }

  return FALSE;
}

/**
 * farsight_stream_set_source_filter:
 * @self: a #FarsightStream
 * @filter: a #GstCaps to use as a filter
 * 
 * Set the GStreamer source link filter for this stream
 *
 * Returns: %TRUE if sucessful
 **/
gboolean 
farsight_stream_set_source_filter (FarsightStream *self, 
                          GstCaps *filter)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self), 
              FARSIGHT_TYPE_STREAM), FALSE);
  g_return_val_if_fail (filter != NULL, FALSE);

  if (klass->set_source_filter ) {
    return klass->set_source_filter (self, filter);
  } else {
    g_warning ("set_source_filter not defined for %s", 
        G_OBJECT_TYPE_NAME (self));
  }
  return FALSE;
}

/**
 * farsight_stream_get_source:
 * @self: a #FarsightStream
 *
 * Get the GStreamer source for this stream
 *
 * Returns: A #GstElement for the current stream source
 **/
GstElement *
farsight_stream_get_source (FarsightStream *self)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self),
              FARSIGHT_TYPE_STREAM), FALSE);

  if (klass->get_source ) {
    return klass->get_source (self);
  } else {
    g_warning ("get_source not defined for %s",
        G_OBJECT_TYPE_NAME (self));
  }
  return NULL;
}

/**
 * farsight_stream_get_state:
 * @self: a #FarsightStream
 *
 * Get the current #FarsightStream state
 *
 * Return value: #FarsightStreamState state
 */
FarsightStreamState farsight_stream_get_state (FarsightStream *self)
{
  return self->priv->state;
}

/**
 * farsight_stream_get_direction:
 * @self: a #FarsightStream
 *
 * Get the #FarsightStream requested direction
 *
 * Return value: #FarsightStreamState direction
 */
FarsightStreamDirection farsight_stream_get_direction (FarsightStream *self)
{
  return self->priv->direction;
}

/**
 * farsight_stream_get_current_direction:
 * @self: a #FarsightStream
 *
 * Get the #FarsightStream current direction
 *
 * Return value: #FarsightStreamState direction
 */
FarsightStreamDirection farsight_stream_get_current_direction (FarsightStream *self)
{
  return self->priv->current_direction;
}

/**
 * farsight_stream_get_media_type:
 * @self: a #FarsightStream
 *
 * Get the #FarsightStream media type
 *
 * Return value: #FarsightMediaType media type
 */
FarsightMediaType farsight_stream_get_media_type (FarsightStream *self)
{
  return self->priv->media_type;
}

/**
 * farsight_stream_get_pipeline:
 * @self: a #FarsightStream
 *
 * Get the #FarsightStream working pipeline. This will return the pipeline set
 * by the user or the pipeline created by Farsight if not set by the user.
 *
 * Return value: #GstElement or NULL if pipeline not available yet
 */
GstElement * farsight_stream_get_pipeline (FarsightStream *self)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self), 
        FARSIGHT_TYPE_STREAM), NULL);

  if (klass->get_pipeline) {
    return klass->get_pipeline (self);
  } else {
    g_warning ("get_pipeline not defined for %s", 
        G_OBJECT_TYPE_NAME (self));
  }
  return NULL; // this shouldn't happen
}

/**
 * farsight_stream_set_pipeline:
 * @self: a #FarsightStream
 * @pipeline: a #GstElement that is a pipeline
 *
 * This function is used if the user wants to create the GstPipeline himself.
 * This means Farsight will use this pipeline instead of creating it's own. It
 * will create a GstBin and insert it into the given pipeline. This is usefull
 * when the user wants all the different Farsight streams to be part of the same
 * global pipeline (i.e. Tee the same source to various streams) If the pipeline
 * is set by the user, the sources will not be added into the Farsight bin.
 *
 * NOTE: This has to be called before farsight_stream_prepare_transports() in
 * order to be used.
 *
 * Return value: %TRUE if successful
 *
 */
gboolean farsight_stream_set_pipeline (FarsightStream *self, GstElement *pipeline)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self), 
        FARSIGHT_TYPE_STREAM), FALSE);
  g_return_val_if_fail (pipeline != NULL, FALSE);

  if (klass->set_pipeline) {
    return klass->set_pipeline (self, pipeline);
  } else {
    g_warning ("set_pipeline not defined for %s", 
        G_OBJECT_TYPE_NAME (self));
  }
  return FALSE; // this shouldn't happen
}

/**
 * farsight_stream_start:
 * @self: a #FarsightStream
 *
 * Start the #FarsightStream streaming to the network
 *
 * Return value: %TRUE if sucessful
 */
gboolean
farsight_stream_start (FarsightStream *self)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self),
              FARSIGHT_TYPE_STREAM), FALSE);

  if (klass->start) {
    return klass->start (self);
  } else {
    g_warning ("start not defined for %s",
        G_OBJECT_TYPE_NAME (self));
  }
  return FALSE;
}

/**
 * farsight_stream_stop:
 * @self: a #FarsightStream
 *
 * Stop the #FarsightStream streaming to the network
 */
void
farsight_stream_stop (FarsightStream *self)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (self), FARSIGHT_TYPE_STREAM));

  if (klass->stop) {
    klass->stop (self);
  } else {
    g_warning ("stop not defined for %s",
        G_OBJECT_TYPE_NAME (self));
  }
}

/**
 * farsight_stream_set_sending:
 * @self: a #FarsightStream
 * @sending: boolean indicating if we should send or not
 *
 * This function will tell Farsight to stop sending. This will block the source
 * pad that is given to Farsight.
 *
 * Return value: %TRUE if successful
 *
 */
gboolean farsight_stream_set_sending (FarsightStream *self, gboolean sending)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self), 
        FARSIGHT_TYPE_STREAM), FALSE);

  if (klass->set_sending) {
    return klass->set_sending (self, sending);
  } else {
    g_warning ("set_sending not defined for %s", 
        G_OBJECT_TYPE_NAME (self));
  }
  return FALSE; // this shouldn't happen
}

gchar *error_messages[FARSIGHT_STREAM_ERROR_LAST + 1] =
{
  gettext_noop ("The stream was terminated"),
  gettext_noop ("An unknown error has occured in the stream"),
  gettext_noop ("Timed out on attempt to establish a connection"),
  gettext_noop ("A network error has occured in the stream"),
  gettext_noop ("An error has occured while setting up the pipeline"),
  gettext_noop ("An error has occured on a required resource"),
};

/**
 * farsight_stream_signal_error:
 * @self: a #FarsightStream
 * @err: #FarsightStreamError value
 * @mesg: a string
 *
 * Used by subclasses of #FarsightStream to emit an
 * <link linkend="FarsightStream-error">error</link> signal
 */
void
farsight_stream_signal_error (FarsightStream *self,
                              FarsightStreamError err,
                              const gchar *msg)
{
  if (!msg)
  {
    msg = gettext (error_messages[err]);
  }
  g_signal_emit (self, signals[ERROR], 0, err, msg);
}

/**
 * farsight_stream_signal_native_candidates_prepared:
 * @self: a #FarsightStream
 *
 * Used by subclasses of #FarsightStream to emit an
 * <link linkend="FarsightStream-native-candidates-prepared">
 * native-candidates-prepared</link> signal
 */
void
farsight_stream_signal_native_candidates_prepared (FarsightStream *self)
{
  g_signal_emit (self, signals[NATIVE_CANDIDATES_PREPARED], 0);
}

/**
 * farsight_stream_signal_new_native_candidate:
 * @self: a #FarsightStream
 * @candidate_id: Identifier of newly discovered native candidate
 *
 * Used by subclasses of #FarsightStream to emit an
 * <link linkend="FarsightStream-new-native-candidate">new-native-candidate
 * </link> signal
 */
void
farsight_stream_signal_new_native_candidate (FarsightStream *self,
                                             const gchar *candidate_id)
{
  g_signal_emit (self, signals[NEW_NATIVE_CANDIDATE], 0, candidate_id);
}

/**
 * farsight_stream_signal_new_active_candidate_pair:
 * @self: a #FarsightStream
 * @native_candidate_id: string identifier of native candidate that is now active
 * @remote_candidate_id: string identifier of remote candidate that is now active
 *
 * Used by subclasses of #FarsightStream to emit an
 * <link linkend="FarsightStream-new-active-candidate-pair">
 * new-active-candidate-pair </link> signal
 */
void
farsight_stream_signal_new_active_candidate_pair (FarsightStream *self,
                                                  const gchar *native_candidate_id,
                                                  const gchar *remote_candidiate_id)
{
  g_signal_emit (self, signals[NEW_ACTIVE_CANDIDATE_PAIR], 0,
                native_candidate_id, remote_candidiate_id);
}

/**
 * farsight_stream_signal_codec_changed:
 * @self: a #FarsightStream
 * @codec_id: id of new codec in use
 *
 * Used by subclasses of #FarsightStream to emit an
 * <link linkend="FarsightStream-codec-changed">codec-changed
 * </link> signal
 */
void 
farsight_stream_signal_codec_changed (FarsightStream *self,
                                      int codec_id)
{
  g_signal_emit (self, signals[CODEC_CHANGED], 0, codec_id);
}

/**
 * farsight_stream_signal_state_changed:
 * @self: a #FarsightStream
 * @state: #FarsightStreamState of new state
 * @direction: #FarsightStreamDirection for directions in
 *
 * Used by subclasses of #FarsightStream to emit an
 * <link linkend="FarsightStream-state-changed">state-changed
 * </link> signal
 */
void farsight_stream_signal_state_changed (FarsightStream *self,
                                           FarsightStreamState state,
                                           FarsightStreamDirection direction)
{
  if (self->priv->state == state && self->priv->current_direction == direction)
    return;
  self->priv->state = state;
  self->priv->current_direction = direction;
  g_signal_emit (self, signals[STATE_CHANGED], 0, state, direction);
}

/**
 * farsight_stream_signal_sink_pad_ready:
 * @self: a #FarsightStream
 * @pad: A GstPad that represents the sink
 *
 * Used by subclasses of #FarsightStream to emit an
 * <link linkend="FarsightStream-sink-pad-ready">sink-pad-ready
 * </link> signal
 */
void farsight_stream_signal_sink_pad_ready (FarsightStream *self,
                                            GstPad *pad)
{
  g_signal_emit (self, signals[SINK_PAD_READY], 0, pad);
}

static void
farsight_stream_set_property (GObject *object,
                              guint prop_id,
                              const GValue *value,
                              GParamSpec *pspec)
{
  FarsightStream *self;

  g_return_if_fail (FARSIGHT_IS_STREAM (object));

  self = FARSIGHT_STREAM (object);

  switch (prop_id) {
    case ARG_MEDIA_TYPE:
      self->priv->media_type = g_value_get_uint (value);
      break;
    case ARG_DIRECTION:
      self->priv->direction = g_value_get_uint (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
farsight_stream_get_property (GObject *object,
                              guint prop_id,
                              GValue *value,
                              GParamSpec *pspec)
{
  FarsightStream *self;

  g_return_if_fail (FARSIGHT_IS_STREAM (object));

  self = FARSIGHT_STREAM (object);

  switch (prop_id) {
    case ARG_MEDIA_TYPE:
      g_value_set_uint (value, self->priv->media_type);
      break;
    case ARG_DIRECTION:
      g_value_set_uint (value, self->priv->direction);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}


/**
 * farsight_stream_start_telephony_event:
 * @self: a #FarsightStream
 * @ev: A #FarsightStreamDTMFEvent or another number defined at
 * http://www.iana.org/assignments/audio-telephone-event-registry
 * @volume: The volume in dBm0 without the negative sign. Should be between
 * 0 and 36. Higher values mean lower volume
 *
 * This function will start sending a telephony event (such as a DTMF
 * tone) on the #FarsightStream, you have to call the function
 * farsight_stream_stop_telephony_event() to stop it. 
 * This function will use any available method, if you want to use a specific
 * method only, use farsight_stream_start_telephony_event_full()
 *
 * Return value: %TRUE if sucessful, it can return %FALSE if the #FarsightStream
 * does not support this telephony event.
 */
gboolean
farsight_stream_start_telephony_event (FarsightStream *self,
                                       guint8 ev,
                                       guint8 volume)
{
  return farsight_stream_start_telephony_event_full (self, ev, volume,
      FARSIGHT_DTMF_METHOD_AUTO);
}


/**
 * farsight_stream_stop_telephony_event:
 * @self: a #FarsightStream
 *
 * This function will stop sending a telephony event started by
 * farsight_stream_start_telephony_event(). If the event was being sent
 * for less than 50ms, it will be sent for 50ms minimum. If the
 * duration was a positive and the event is not over, it will cut it
 * short.
 *
 * Return value: %TRUE if sucessful, it can return %FALSE if the #FarsightStream
 * does not support telephony events or if no telephony event is being sent
 */
gboolean
farsight_stream_stop_telephony_event (FarsightStream *self)
{
  return farsight_stream_stop_telephony_event_full (self, FARSIGHT_DTMF_METHOD_AUTO);
}


/**
 * farsight_stream_start_telephony_event_full:
 * @self: a #FarsightStream
 * @ev: A #FarsightStreamDTMFEvent or another number defined at
 * http://www.iana.org/assignments/audio-telephone-event-registry
 * @volume: The volume in dBm0 without the negative sign. Should be between
 * 0 and 36. Higher values mean lower volume
 * @type: The way the event should be sent
 * @method: The method used to send the event
 *
 * This function will start sending a telephony event (such as a DTMF
 * tone) on the #FarsightStream, you have to call the function
 * farsight_stream_stop_telephony_event_full() to stop it.
 *
 * Return value: %TRUE if sucessful, it can return %FALSE if the #FarsightStream
 * does not support this telephony event.
 */
gboolean
farsight_stream_start_telephony_event_full (FarsightStream *self,
    guint8 ev, guint8 volume, FarsightStreamDTMFMethod method)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self),
              FARSIGHT_TYPE_STREAM), FALSE);

  if (klass->start_telephony_event) {
    return klass->start_telephony_event (self, ev, volume, method);
  }

  return FALSE;
}


/**
 * farsight_stream_stop_telephony_event_full:
 * @self: a #FarsightStream
 * @method: The method used to send the event, this MUST match the parameter
 * passed to farsight_stream_start_telephony_event_full().
 *
 * This function will stop sending a telephony event started by
 * farsight_stream_start_telephony_event_full(). If the event was being sent
 * for less than 50ms, it will be sent for 50ms minimum. If the
 * duration was a positive and the event is not over, it will cut it
 * short. The type parameters has to be the same type that was passed to
 *
 * Return value: %TRUE if sucessful, it can return %FALSE if the #FarsightStream
 * does not support telephony events or if no telephony event is being sent
 */
gboolean
farsight_stream_stop_telephony_event_full (FarsightStream *self,
                                           FarsightStreamDTMFMethod method)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self),
              FARSIGHT_TYPE_STREAM), FALSE);

  if (klass->stop_telephony_event) {
    return klass->stop_telephony_event (self, method);
  }

  return FALSE;
}

/**
 * farsight_stream_preload_receive_pipeline
 * @self: a #FarsightStream
 * @payload_type: The payload type for which to preload the codec
 *
 * This function will preload a codec instead of loading it when the first
 * codec arrives. It is particularly useful with DSP and other slow to load
 * and initialise codecs.
 *
 * Return value: TRUE if sucessful, it can return FALSE if the #FarsightStream
 * is already receiving packets or if the codec can not be preloaded.
 */

gboolean farsight_stream_preload_receive_pipeline (
    FarsightStream *self, gint payload_type)
{
  FarsightStreamClass *klass = FARSIGHT_STREAM_GET_CLASS (self);
  g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (self),
          FARSIGHT_TYPE_STREAM), FALSE);

  if (klass->preload_receive_pipeline) {
    return klass->preload_receive_pipeline (self, payload_type);
  }

  return FALSE;
}

Generated by  Doxygen 1.6.0   Back to index