Beispiel #1
0
/**
 * fs_rtp_stream_set_negotiated_codecs_unlock
 * @stream: a #FsRtpStream
 * @codecs: The #GList of #FsCodec to set for the negotiated-codecs property
 *
 * This function sets the value of the FsStream:negotiated-codecs property.
 * Unlike most other functions in this element, it TAKES the reference to the
 * codecs, so you have to give it its own copy.
 *
 * You must enter this function with the session lock held and it will release
 * it.
 */
void
fs_rtp_stream_set_negotiated_codecs_unlock (FsRtpStream *stream,
    GList *codecs)
{
  FsRtpSession *session = fs_rtp_stream_get_session (stream, NULL);

  if (!session)
    return;

  if (fs_codec_list_are_equal (stream->negotiated_codecs, codecs))
  {
    fs_codec_list_destroy (codecs);
    FS_RTP_SESSION_UNLOCK (session);
    g_object_unref (session);
    return;
  }

  if (stream->negotiated_codecs)
    fs_codec_list_destroy (stream->negotiated_codecs);

  stream->negotiated_codecs = codecs;

  FS_RTP_SESSION_UNLOCK (session);

  g_object_notify (G_OBJECT (stream), "negotiated-codecs");

  g_object_unref (session);
}
static gboolean
_rtpbin_pad_have_data_callback (GstPad *pad, GstMiniObject *miniobj,
    gpointer user_data)
{
  FsRtpSubStream *self = FS_RTP_SUB_STREAM (user_data);
  gboolean ret = TRUE;
  gboolean remove = FALSE;
  FsRtpSession *session;

  if (fs_rtp_session_has_disposed_enter (self->priv->session, NULL))
    return FALSE;

  if (fs_rtp_sub_stream_has_stopped_enter (self))
  {
    fs_rtp_session_has_disposed_exit (self->priv->session);
    return FALSE;
  }

  g_object_ref (self);
  session = g_object_ref (self->priv->session);

  FS_RTP_SESSION_LOCK (self->priv->session);

  if (!self->priv->codecbin || !self->codec || !self->priv->caps)
  {
    ret = FALSE;
  }
  else if (GST_IS_BUFFER (miniobj))
  {
    if (!gst_caps_is_equal_fixed (GST_BUFFER_CAPS (miniobj), self->priv->caps))
    {
      if (!gst_caps_can_intersect (GST_BUFFER_CAPS (miniobj),
              self->priv->caps))
        ret = FALSE;
    }
    else
    {
      remove = TRUE;
    }
  }

  if (remove && self->priv->blocking_id)
  {
    gst_pad_remove_data_probe (pad, self->priv->blocking_id);
    self->priv->blocking_id = 0;
  }

  FS_RTP_SESSION_UNLOCK (self->priv->session);

  fs_rtp_sub_stream_has_stopped_exit (self);

  fs_rtp_session_has_disposed_exit (self->priv->session);

  g_object_unref (self);
  g_object_unref (session);

  return ret;
}
Beispiel #3
0
static void
_substream_unlinked (FsRtpSubStream *substream, gpointer user_data)
{
  FsRtpStream *stream = FS_RTP_STREAM (user_data);
  FsRtpSession *session =  fs_rtp_stream_get_session (stream, NULL);

  if (!session)
    return;

  FS_RTP_SESSION_LOCK (session);
  stream->substreams = g_list_remove (stream->substreams,
      substream);
  FS_RTP_SESSION_UNLOCK (session);

  fs_rtp_sub_stream_stop (substream);

  g_object_unref (substream);
  g_object_unref (session);
}
Beispiel #4
0
static gboolean
_rtpbin_pad_have_data_callback (GstPad *pad, GstMiniObject *miniobj,
    gpointer user_data)
{
  FsRtpSubStream *self = FS_RTP_SUB_STREAM (user_data);
  gboolean ret = TRUE;
  gboolean remove = FALSE;

  FS_RTP_SESSION_LOCK (self->priv->session);

  if (!self->priv->codecbin || !self->codec || !self->priv->caps)
  {
    ret = FALSE;
  }
  else if (GST_IS_BUFFER (miniobj))
  {
    if (!gst_caps_is_equal_fixed (GST_BUFFER_CAPS (miniobj), self->priv->caps))
    {
      GstCaps *intersect = gst_caps_intersect (GST_BUFFER_CAPS (miniobj),
          self->priv->caps);

      if (gst_caps_is_empty (intersect))
        ret = FALSE;
      else
        gst_buffer_set_caps (GST_BUFFER (miniobj), self->priv->caps);
      gst_caps_unref (intersect);
    }
    else
    {
      remove = TRUE;
    }
  }

  if (remove && self->priv->blocking_id)
  {
    gst_pad_remove_data_probe (pad, self->priv->blocking_id);
    self->priv->blocking_id = 0;
  }

  FS_RTP_SESSION_UNLOCK (self->priv->session);

  return ret;
}
static gboolean
fs_rtp_sub_stream_start_no_rtcp_timeout_thread (FsRtpSubStream *self,
    GError **error)
{
  gboolean res = TRUE;
  GstClock *sysclock = NULL;

  sysclock = gst_system_clock_obtain ();
  if (sysclock == NULL)
  {
    g_set_error (error, FS_ERROR, FS_ERROR_INTERNAL,
        "Could not obtain gst system clock");
    return FALSE;
  }

  FS_RTP_SESSION_LOCK (self->priv->session);
  FS_RTP_SUB_STREAM_LOCK(self);

  self->priv->next_no_rtcp_timeout = gst_clock_get_time (sysclock) +
    (self->no_rtcp_timeout * GST_MSECOND);

  gst_object_unref (sysclock);

  if (self->priv->no_rtcp_timeout_thread == NULL) {
    /* only create a new thread if the old one was stopped. Otherwise we can
     * just reuse the currently running one. */
    self->priv->no_rtcp_timeout_thread =
      g_thread_create (no_rtcp_timeout_func, self, TRUE, error);
  }

  res = (self->priv->no_rtcp_timeout_thread != NULL);

  if (res == FALSE && error && *error == NULL)
    g_set_error (error, FS_ERROR, FS_ERROR_INTERNAL, "Unknown error creating"
        " thread");

  FS_RTP_SUB_STREAM_UNLOCK(self);
  FS_RTP_SESSION_UNLOCK (self->priv->session);

  return res;
}
Beispiel #6
0
/**
 * fs_rtp_stream_add_substream_unlock:
 * @stream: a #FsRtpStream
 * @substream: the #FsRtpSubStream to associate with this stream
 *
 * This functions associates a substream with this stream
 *
 * You must enter this function with the session lock held and it will release
 * it.
 *
 * Returns: TRUE on success, FALSE on failure
 */
gboolean
fs_rtp_stream_add_substream_unlock (FsRtpStream *stream,
    FsRtpSubStream *substream,
    GError **error)
{
  gboolean ret = TRUE;
  FsRtpSession *session = fs_rtp_stream_get_session (stream, error);

  if (!session)
    return FALSE;

  stream->substreams = g_list_prepend (stream->substreams,
      substream);
  g_object_set (substream,
      "stream", stream,
      "receiving", ((stream->priv->direction & FS_DIRECTION_RECV) != 0),
      NULL);

  g_signal_connect_object (substream, "unlinked",
      G_CALLBACK (_substream_unlinked), stream, 0);
  g_signal_connect_object (substream, "src-pad-added",
      G_CALLBACK (_substream_src_pad_added), stream, 0);
  g_signal_connect_object (substream, "codec-changed",
      G_CALLBACK (_substream_codec_changed), stream, 0);
  g_signal_connect_object (substream, "error",
      G_CALLBACK (_substream_error), stream, 0);

  fs_rtp_sub_stream_verify_codec_locked (substream);

  /* Only announce a pad if it has a codec attached to it */
  if (substream->codec)
    ret = fs_rtp_sub_stream_add_output_ghostpad_unlock (substream, error);
  else
    FS_RTP_SESSION_UNLOCK (session);

  g_object_unref (session);

  return ret;
}
Beispiel #7
0
static FsStreamTransmitter *
fs_rtp_stream_get_stream_transmitter (FsRtpStream *self, GError **error)
{
  FsRtpSession *session = fs_rtp_stream_get_session (self, error);
  FsStreamTransmitter *st = NULL;

  if (!session)
    return NULL;

  FS_RTP_SESSION_LOCK (session);
  st = self->priv->stream_transmitter;
  if (st)
    g_object_ref (st);
  FS_RTP_SESSION_UNLOCK (session);

  if (!st)
    g_set_error (error, FS_ERROR, FS_ERROR_DISPOSED,
        "Stream transmitter not set (or stream has been disposed)");

  g_object_unref (session);
  return st;
}
Beispiel #8
0
static void
_substream_codec_changed (FsRtpSubStream *substream,
    FsRtpStream *stream)
{
  GList *substream_item = NULL;
  GList *codeclist = NULL;
  FsRtpSession *session = fs_rtp_stream_get_session (stream, NULL);

  if (!session)
    return;

  FS_RTP_SESSION_LOCK (session);

  if (!substream->codec)
  {
    FS_RTP_SESSION_UNLOCK (session);
    g_object_unref (session);
    return;
  }

  codeclist = g_list_prepend (NULL, fs_codec_copy (substream->codec));

  for (substream_item = stream->substreams;
       substream_item;
       substream_item = g_list_next (substream_item))
  {
    FsRtpSubStream *othersubstream = substream_item->data;

    if (othersubstream != substream)
    {
      if (othersubstream->codec)
      {
        if (fs_codec_are_equal (substream->codec, othersubstream->codec))
          break;

        if (!_codec_list_has_codec (codeclist, othersubstream->codec))
          codeclist = g_list_append (codeclist,
              fs_codec_copy (othersubstream->codec));
      }
    }
  }

  FS_RTP_SESSION_UNLOCK (session);

  if (substream_item == NULL)
  {
    GstElement *conf = NULL;

    g_object_notify (G_OBJECT (stream), "current-recv-codecs");

    g_object_get (session, "conference", &conf, NULL);

    gst_element_post_message (conf,
        gst_message_new_element (GST_OBJECT (conf),
            gst_structure_new ("farstream-recv-codecs-changed",
                "stream", FS_TYPE_STREAM, stream,
                "codecs", FS_TYPE_CODEC_LIST, codeclist,
                NULL)));

    gst_object_unref (conf);
  }

  fs_codec_list_destroy (codeclist);
  g_object_unref (session);
}
Beispiel #9
0
/**
 * fs_rtp_stream_set_remote_codecs:
 * @stream: an #FsStream
 * @remote_codecs: a #GList of #FsCodec representing the remote codecs
 * @error: location of a #GError, or NULL if no error occured
 *
 * This function will set the list of remote codecs for this stream. If
 * the given remote codecs couldn't be negotiated with the list of local
 * codecs or already negotiated codecs for the corresponding #FsSession, @error
 * will be set and %FALSE will be returned. The @remote_codecs list will be
 * copied so it must be free'd using fs_codec_list_destroy() when done.
 *
 * Returns: %FALSE if the remote codecs couldn't be set.
 */
static gboolean
fs_rtp_stream_set_remote_codecs (FsStream *stream,
                                 GList *remote_codecs, GError **error)
{
  FsRtpStream *self = FS_RTP_STREAM (stream);
  GList *item = NULL;
  FsMediaType media_type;
  FsRtpSession *session = fs_rtp_stream_get_session (self, error);

  if (!session)
    return FALSE;

  if (remote_codecs == NULL) {
    g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
      "You can not set NULL remote codecs");
    goto error;
  }

  g_object_get (session, "media-type", &media_type, NULL);

  for (item = g_list_first (remote_codecs); item; item = g_list_next (item))
  {
    FsCodec *codec = item->data;

    if (!codec->encoding_name)
    {
      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
          "The codec must have an encoding name");
      goto error;
    }
    if (codec->id < 0 || codec->id > 128)
    {
      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
          "The codec id must be between 0 ans 128 for %s",
          codec->encoding_name);
      goto error;
    }
    if (codec->media_type != media_type)
    {
      g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
          "The media type for codec %s is not %s", codec->encoding_name,
          fs_media_type_to_string (media_type));
      goto error;
    }
  }

  if (self->priv->new_remote_codecs_cb (self, remote_codecs, error,
          self->priv->user_data_for_cb))
  {
    gboolean is_new = TRUE;

    FS_RTP_SESSION_LOCK (session);
    if (self->remote_codecs)
    {
      is_new = !fs_codec_list_are_equal (self->remote_codecs, remote_codecs);
      fs_codec_list_destroy (self->remote_codecs);
    }
    self->remote_codecs = fs_codec_list_copy (remote_codecs);
    FS_RTP_SESSION_UNLOCK (session);

    if (is_new)
      g_object_notify (G_OBJECT (stream), "remote-codecs");
  } else {
    goto error;
  }

  g_object_unref (session);
  return TRUE;

 error:

  g_object_unref (session);
  return FALSE;
}
Beispiel #10
0
static void
fs_rtp_stream_set_property (GObject *object,
                            guint prop_id,
                            const GValue *value,
                            GParamSpec *pspec)
{
  FsRtpStream *self = FS_RTP_STREAM (object);
  GList *item;

  switch (prop_id) {
    case PROP_SESSION:
      self->priv->session = FS_RTP_SESSION (g_value_dup_object (value));
      break;
    case PROP_PARTICIPANT:
      self->participant = FS_RTP_PARTICIPANT (g_value_dup_object (value));
      break;
    case PROP_DIRECTION:
      {
        FsStreamTransmitter *st = NULL;
        GList *copy = NULL;
        FsRtpSession *session = fs_rtp_stream_get_session (self, NULL);
        FsStreamDirection dir;

        if (!session)
        {
          self->priv->direction = g_value_get_flags (value);
          return;
        }

        FS_RTP_SESSION_LOCK (session);
        if (self->priv->sending_changed_locked_cb &&
            (self->priv->direction & FS_DIRECTION_SEND) !=
            (g_value_get_flags (value) & FS_DIRECTION_SEND))
          self->priv->sending_changed_locked_cb (self,
              g_value_get_flags (value) & FS_DIRECTION_SEND,
              self->priv->user_data_for_cb);

        dir = self->priv->direction = g_value_get_flags (value);
        FS_RTP_SESSION_UNLOCK (session);
        st = fs_rtp_stream_get_stream_transmitter (self, NULL);
        if (st)
        {
          g_object_set (self->priv->stream_transmitter, "sending",
              dir & FS_DIRECTION_SEND, NULL);
          g_object_unref (st);
        }

        FS_RTP_SESSION_LOCK (session);
        copy = g_list_copy (g_list_first (self->substreams));
        g_list_foreach (copy, (GFunc) g_object_ref, NULL);
        FS_RTP_SESSION_UNLOCK (session);

        for (item = copy;  item; item = g_list_next (item))
          g_object_set (G_OBJECT (item->data),
              "receiving", ((dir & FS_DIRECTION_RECV) != 0),
              NULL);
        g_list_foreach (copy, (GFunc) g_object_unref, NULL);
        g_list_free (copy);
        g_object_unref (session);
      }
      break;
    case PROP_RTP_HEADER_EXTENSIONS:
      {
        FsRtpSession *session = fs_rtp_stream_get_session (self, NULL);
        if (session)
        {
          FS_RTP_SESSION_LOCK (session);
          fs_rtp_header_extension_list_destroy (self->hdrext);
          self->hdrext = g_value_dup_boxed (value);
          FS_RTP_SESSION_UNLOCK (session);
          /* The callbadck can not fail because it does not change
           * the codecs
           */
          self->priv->new_remote_codecs_cb (NULL, NULL, NULL,
              self->priv->user_data_for_cb);
          g_object_unref (session);
        }
      }
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }

}
Beispiel #11
0
static void
fs_rtp_stream_get_property (GObject *object,
                            guint prop_id,
                            GValue *value,
                            GParamSpec *pspec)
{
  FsRtpStream *self = FS_RTP_STREAM (object);
  FsRtpSession *session = fs_rtp_stream_get_session (self, NULL);

  if (!session)
    return;

  switch (prop_id) {
    case PROP_REMOTE_CODECS:
      FS_RTP_SESSION_LOCK (session);
      g_value_set_boxed (value, self->remote_codecs);
      FS_RTP_SESSION_UNLOCK (session);
      break;
    case PROP_NEGOTIATED_CODECS:
      FS_RTP_SESSION_LOCK (session);
      g_value_set_boxed (value, self->negotiated_codecs);
      FS_RTP_SESSION_UNLOCK (session);
      break;
    case PROP_SESSION:
      g_value_set_object (value, session);
      break;
    case PROP_PARTICIPANT:
      FS_RTP_SESSION_LOCK (session);
      g_value_set_object (value, self->participant);
      FS_RTP_SESSION_UNLOCK (session);
      break;
    case PROP_DIRECTION:
      g_value_set_flags (value, self->priv->direction);
      break;
    case PROP_CURRENT_RECV_CODECS:
      {
        GList *codeclist = NULL;
        GList *substream_item;

        FS_RTP_SESSION_LOCK (session);
        for (substream_item = g_list_first (self->substreams);
             substream_item;
             substream_item = g_list_next (substream_item))
        {
          FsRtpSubStream *substream = substream_item->data;

          if (substream->codec)
          {
            if (!_codec_list_has_codec (codeclist, substream->codec))
              codeclist = g_list_append (codeclist,
                  fs_codec_copy (substream->codec));
          }
        }

        g_value_take_boxed (value, codeclist);
        FS_RTP_SESSION_UNLOCK (session);
      }
      break;
    case PROP_RTP_HEADER_EXTENSIONS:
      FS_RTP_SESSION_LOCK (session);
      g_value_set_boxed (value, self->hdrext);
      FS_RTP_SESSION_UNLOCK (session);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }

  g_object_unref (session);
}
Beispiel #12
0
static void
fs_rtp_stream_dispose (GObject *object)
{
  FsRtpStream *self = FS_RTP_STREAM (object);
  FsStreamTransmitter *st;
  FsRtpParticipant *participant;
  FsRtpSession *session = fs_rtp_stream_get_session (self, NULL);

  if (!session)
    return;

  g_mutex_lock (&self->priv->mutex);
  self->priv->session = NULL;
  g_mutex_unlock (&self->priv->mutex);

  FS_RTP_SESSION_LOCK (session);

  if (self->priv->sending_changed_locked_cb &&
      self->priv->direction & FS_DIRECTION_SEND)
    self->priv->sending_changed_locked_cb (self, FALSE,
        self->priv->user_data_for_cb);

  participant = self->participant;
  self->participant = NULL;

  st = self->priv->stream_transmitter;
  self->priv->stream_transmitter = NULL;

  if (st)
  {
    g_signal_handler_disconnect (st,
        self->priv->local_candidates_prepared_handler_id);
    g_signal_handler_disconnect (st,
        self->priv->new_active_candidate_pair_handler_id);
    g_signal_handler_disconnect (st,
        self->priv->new_local_candidate_handler_id);
    g_signal_handler_disconnect (st,
        self->priv->error_handler_id);
    g_signal_handler_disconnect (st,
        self->priv->known_source_packet_received_handler_id);
    g_signal_handler_disconnect (st,
        self->priv->state_changed_handler_id);

    FS_RTP_SESSION_UNLOCK (session);
    fs_stream_transmitter_stop (st);
    g_object_unref (st);
    FS_RTP_SESSION_LOCK (session);
  }

  while (self->substreams)
  {
    FsRtpSubStream *substream = self->substreams->data;
    self->substreams = g_list_remove (self->substreams, substream);
    FS_RTP_SESSION_UNLOCK (session);
    g_object_unref (substream);
    FS_RTP_SESSION_LOCK (session);
  }

  FS_RTP_SESSION_UNLOCK (session);

  g_object_unref (participant);
  g_object_unref (session);
  g_object_unref (session);

  G_OBJECT_CLASS (fs_rtp_stream_parent_class)->dispose (object);
}
Beispiel #13
0
static gboolean
fs_rtp_stream_set_transmitter (FsStream *stream,
    const gchar *transmitter,
    GParameter *stream_transmitter_parameters,
    guint stream_transmitter_n_parameters,
    GError **error)
{
  FsStreamTransmitter *st = NULL;
  FsRtpStream *self = FS_RTP_STREAM (stream);
  FsRtpSession *session = fs_rtp_stream_get_session (self, error);

  if (!session)
    return FALSE;

  FS_RTP_SESSION_LOCK (session);
  if (self->priv->stream_transmitter)
  {
    FS_RTP_SESSION_UNLOCK (session);
    g_object_unref (session);
    return FALSE;
  }
  FS_RTP_SESSION_UNLOCK (session);

  st = self->priv->get_new_stream_transmitter_cb (self,
      FS_PARTICIPANT (self->participant), transmitter,
      stream_transmitter_parameters, stream_transmitter_n_parameters, error,
      self->priv->user_data_for_cb);

  if (!st)
  {
    g_object_unref (session);
    return FALSE;
  }


  g_object_set (st, "sending",
    self->priv->direction & FS_DIRECTION_SEND, NULL);

  self->priv->local_candidates_prepared_handler_id =
    g_signal_connect_object (st,
        "local-candidates-prepared",
        G_CALLBACK (_local_candidates_prepared),
        self, 0);
  self->priv->new_active_candidate_pair_handler_id =
    g_signal_connect_object (st,
        "new-active-candidate-pair",
        G_CALLBACK (_new_active_candidate_pair),
        self, 0);
  self->priv->new_local_candidate_handler_id =
    g_signal_connect_object (st,
        "new-local-candidate",
        G_CALLBACK (_new_local_candidate),
        self, 0);
  self->priv->error_handler_id =
    g_signal_connect_object (st,
        "error",
        G_CALLBACK (_transmitter_error),
        self, 0);
  self->priv->known_source_packet_received_handler_id =
    g_signal_connect_object (st,
        "known-source-packet-received",
        G_CALLBACK (_known_source_packet_received),
        self, 0);
  self->priv->state_changed_handler_id =
    g_signal_connect_object (st,
        "state-changed",
        G_CALLBACK (_state_changed),
        self, 0);


  FS_RTP_SESSION_LOCK (session);
  self->priv->stream_transmitter = st;
  if (self->priv->direction & FS_DIRECTION_SEND)
    self->priv->sending_changed_locked_cb (self,
        self->priv->direction & FS_DIRECTION_SEND,
        self->priv->user_data_for_cb);
  FS_RTP_SESSION_UNLOCK (session);

  if (!fs_stream_transmitter_gather_local_candidates (st, error))
  {

    FS_RTP_SESSION_LOCK (session);
    self->priv->stream_transmitter = NULL;
    FS_RTP_SESSION_UNLOCK (session);
    g_object_unref (st);
    g_object_unref (session);
    return FALSE;
  }

  g_object_unref (session);
  return TRUE;
}
Beispiel #14
0
static gboolean
fs_rtp_sub_stream_set_codecbin (FsRtpSubStream *substream,
    FsCodec *codec,
    GstElement *codecbin,
    GError **error)
{
  GstCaps *caps = NULL;
  gchar *tmp;
  gboolean ret = FALSE;
  GstPad *pad;

  if (substream->priv->codecbin)
  {
    gst_element_set_locked_state (substream->priv->codecbin, TRUE);
    if (gst_element_set_state (substream->priv->codecbin, GST_STATE_NULL) !=
        GST_STATE_CHANGE_SUCCESS)
    {
      gst_element_set_locked_state (substream->priv->codecbin, FALSE);
      g_set_error (error, FS_ERROR, FS_ERROR_INTERNAL,
          "Could not set the codec bin for ssrc %u"
          " and payload type %d to the state NULL", substream->ssrc,
          substream->pt);
      gst_object_unref (codecbin);
      fs_codec_destroy (codec);
      return FALSE;
    }

    gst_bin_remove (GST_BIN (substream->priv->conference),
        substream->priv->codecbin);

    FS_RTP_SESSION_LOCK (substream->priv->session);
    substream->priv->codecbin = NULL;
    if (substream->codec)
    {
      fs_codec_destroy (substream->codec);
      substream->codec = NULL;
    }

    if (substream->priv->caps)
      gst_caps_unref (substream->priv->caps);
    substream->priv->caps = NULL;
    FS_RTP_SESSION_UNLOCK (substream->priv->session);
  }


  if (!gst_bin_add (GST_BIN (substream->priv->conference), codecbin))
  {
    gst_object_unref (codecbin);
    fs_codec_destroy (codec);
    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
      "Could not add the codec bin to the conference");
    return FALSE;
  }

  if (gst_element_set_state (codecbin, GST_STATE_PLAYING) ==
      GST_STATE_CHANGE_FAILURE)
  {
    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
      "Could not set the codec bin to the playing state");
    goto error;
  }

  if (!gst_element_link_pads (codecbin, "src",
      substream->priv->output_valve, "sink"))
  {
    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
      "Could not link the codec bin to the output_valve");
    goto error;
  }

  if (!gst_element_link_pads (substream->priv->capsfilter, "src",
          codecbin, "sink"))
  {
     g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
         "Could not link the receive capsfilter and the codecbin for pt %d",
         substream->pt);
    goto error;
  }

  caps = fs_codec_to_gst_caps (codec);
  tmp = gst_caps_to_string (caps);
  GST_DEBUG ("Setting caps %s on recv substream", tmp);
  g_free (tmp);
  g_object_set (substream->priv->capsfilter, "caps", caps, NULL);

  pad = gst_element_get_static_pad (codecbin, "sink");
  if (!pad)
  {
    g_set_error (error, FS_ERROR, FS_ERROR_INTERNAL, "Could not get sink pad"
        " from codecbin");
    goto error;
  }

  /* This is a non-error error
   * Some codecs require config data to start.. so we should just ignore them
   */
  if (!gst_pad_set_caps (pad, caps))
  {
    ret = TRUE;
    gst_object_unref (pad);
    gst_caps_unref (caps);

    GST_DEBUG ("Could not set the caps on the codecbin, waiting on config-data"
        " for SSRC:%x pt:%d", substream->ssrc, substream->pt);

    /* We call this to drop all buffers until something comes up */
    fs_rtp_sub_stream_add_probe_locked (substream);
    goto error;
  }

  GST_DEBUG ("New recv codec accepted");

  gst_object_unref (pad);

  FS_RTP_SESSION_LOCK (substream->priv->session);
  substream->priv->caps = caps;
  substream->priv->codecbin = codecbin;
  substream->codec = codec;
  codec = NULL;

  if (substream->priv->stream && !substream->priv->output_ghostpad)
  {
    if (!fs_rtp_sub_stream_add_output_ghostpad_unlock (substream, error))
      goto error;
  }
  else
  {
    FS_RTP_SESSION_UNLOCK (substream->priv->session);
    g_signal_emit (substream, signals[CODEC_CHANGED], 0);
  }


  return TRUE;

 error:

  gst_element_set_locked_state (codecbin, TRUE);
  gst_element_set_state (codecbin, GST_STATE_NULL);
  gst_bin_remove (GST_BIN (substream->priv->conference), codecbin);

  fs_codec_destroy (codec);

  return ret;
}
Beispiel #15
0
gboolean
fs_rtp_sub_stream_add_output_ghostpad_unlock (FsRtpSubStream *substream,
    GError **error)
{
  GstPad *valve_srcpad;
  gchar *padname = NULL;
  GstPad *ghostpad = NULL;
  FsCodec *codec = NULL;

  if (fs_rtp_sub_stream_has_stopped_enter (substream))
  {
    FS_RTP_SESSION_UNLOCK (substream->priv->session);
    return TRUE;
  }

  if (substream->priv->adding_output_ghostpad)
  {
    FS_RTP_SESSION_UNLOCK (substream->priv->session);
    goto out;
  }

  g_assert (substream->priv->output_ghostpad == NULL);

  substream->priv->adding_output_ghostpad = TRUE;

  padname = g_strdup_printf ("src_%u_%u_%d", substream->priv->session->id,
      substream->ssrc,
      substream->pt);

  FS_RTP_SESSION_UNLOCK (substream->priv->session);

  valve_srcpad = gst_element_get_static_pad (substream->priv->output_valve,
      "src");
  g_assert (valve_srcpad);

  ghostpad = gst_ghost_pad_new_from_template (padname, valve_srcpad,
      gst_element_class_get_pad_template (
          GST_ELEMENT_GET_CLASS (substream->priv->conference),
          "src_%d_%d_%d"));

  gst_object_unref (valve_srcpad);
  g_free (padname);

  if (!ghostpad)
  {
    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
        "Could not build ghostpad src_%u_%u_%d", substream->priv->session->id,
        substream->ssrc, substream->pt);
    goto error;
  }

  if (!gst_pad_set_active (ghostpad, TRUE))
  {
    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
        "Could not activate the src_%u_%u_%d", substream->priv->session->id,
        substream->ssrc, substream->pt);
    gst_object_unref (ghostpad);
    goto error;
  }

  if (!gst_element_add_pad (GST_ELEMENT (substream->priv->conference),
          ghostpad))
  {
    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
        "Could add build ghostpad src_%u_%u_%d to the conference",
        substream->priv->session->id, substream->ssrc, substream->pt);
    gst_object_unref (ghostpad);
    goto error;
  }

  FS_RTP_SESSION_LOCK (substream->priv->session);
  substream->priv->output_ghostpad = ghostpad;

  GST_DEBUG ("Src pad added on substream for ssrc:%X pt:%u " FS_CODEC_FORMAT,
      substream->ssrc, substream->pt,
      FS_CODEC_ARGS (substream->codec));

  codec = fs_codec_copy (substream->codec);

  FS_RTP_SESSION_UNLOCK (substream->priv->session);

  g_signal_emit (substream, signals[SRC_PAD_ADDED], 0,
                 ghostpad, codec);
  g_signal_emit (substream, signals[CODEC_CHANGED], 0);

  fs_codec_destroy (codec);

  g_object_set (substream->priv->output_valve, "drop", FALSE, NULL);

 out:

  fs_rtp_sub_stream_has_stopped_exit (substream);
  return TRUE;

 error:

  substream->priv->adding_output_ghostpad = FALSE;
  fs_rtp_sub_stream_has_stopped_exit (substream);
  return FALSE;
}