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 #2
0
static void
fs_rtp_sub_stream_dispose (GObject *object)
{
  FsRtpSubStream *self = FS_RTP_SUB_STREAM (object);

  fs_rtp_sub_stream_stop (self);

  fs_rtp_sub_stream_stop_no_rtcp_timeout_thread (self);

  if (self->priv->output_ghostpad) {
    gst_element_remove_pad (GST_ELEMENT (self->priv->conference),
      self->priv->output_ghostpad);
    self->priv->output_ghostpad = NULL;
  }

  if (self->priv->output_valve) {
    gst_element_set_locked_state (self->priv->output_valve, TRUE);
    gst_element_set_state (self->priv->output_valve, GST_STATE_NULL);
    gst_bin_remove (GST_BIN (self->priv->conference), self->priv->output_valve);
    self->priv->output_valve = NULL;
  }

  if (self->priv->codecbin) {
    gst_element_set_locked_state (self->priv->codecbin, TRUE);
    gst_element_set_state (self->priv->codecbin, GST_STATE_NULL);
    gst_bin_remove (GST_BIN (self->priv->conference), self->priv->codecbin);
    self->priv->codecbin = NULL;
  }

  if (self->priv->capsfilter) {
    gst_element_set_locked_state (self->priv->capsfilter, TRUE);
    gst_element_set_state (self->priv->capsfilter, GST_STATE_NULL);
    gst_bin_remove (GST_BIN (self->priv->conference), self->priv->capsfilter);
    self->priv->capsfilter = NULL;
  }

  if (self->priv->input_valve) {
    gst_element_set_locked_state (self->priv->input_valve, TRUE);
    gst_element_set_state (self->priv->input_valve, GST_STATE_NULL);
    gst_bin_remove (GST_BIN (self->priv->conference), self->priv->input_valve);
    self->priv->input_valve = NULL;
  }

  if (self->priv->blocking_id)
  {
    gst_pad_remove_data_probe (self->priv->rtpbin_pad,
        self->priv->blocking_id);
    self->priv->blocking_id = 0;
  }

  if (self->priv->rtpbin_pad) {
    gst_object_unref (self->priv->rtpbin_pad);
    self->priv->rtpbin_pad = NULL;
  }

  self->priv->disposed = TRUE;
  G_OBJECT_CLASS (fs_rtp_sub_stream_parent_class)->dispose (object);
}
static void
fs_rtp_sub_stream_finalize (GObject *object)
{
  FsRtpSubStream *self = FS_RTP_SUB_STREAM (object);

  if (self->codec)
    fs_codec_destroy (self->codec);

  if (self->priv->caps)
    gst_caps_unref (self->priv->caps);

  if (self->priv->mutex)
    g_mutex_free (self->priv->mutex);

  G_OBJECT_CLASS (fs_rtp_sub_stream_parent_class)->finalize (object);
}
static void
fs_rtp_sub_stream_set_property (GObject *object,
                                guint prop_id,
                                const GValue *value,
                                GParamSpec *pspec)
{
  FsRtpSubStream *self = FS_RTP_SUB_STREAM (object);

  switch (prop_id) {
    case PROP_CONFERENCE:
      self->priv->conference = g_value_get_object (value);
      break;
    case PROP_SESSION:
      self->priv->session = g_value_get_object (value);
      break;
    case PROP_STREAM:
      if (self->priv->stream)
        GST_WARNING ("Stream already set, not re-setting");
      else
        self->priv->stream = g_value_get_object (value);
      break;
    case PROP_RTPBIN_PAD:
      self->priv->rtpbin_pad = GST_PAD (g_value_dup_object (value));
      break;
    case PROP_SSRC:
      self->ssrc = g_value_get_uint (value);
      break;
    case PROP_PT:
      self->pt = g_value_get_uint (value);
      break;
    case PROP_RECEIVING:
      self->priv->receiving = g_value_get_boolean (value);
      if (self->priv->input_valve)
        g_object_set (G_OBJECT (self->priv->input_valve),
            "drop", !self->priv->receiving,
            NULL);
      break;
    case PROP_NO_RTCP_TIMEOUT:
      self->no_rtcp_timeout = g_value_get_int (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
static void
fs_rtp_sub_stream_get_property (GObject *object,
                                guint prop_id,
                                GValue *value,
                                GParamSpec *pspec)
{
  FsRtpSubStream *self = FS_RTP_SUB_STREAM (object);

  switch (prop_id) {
    case PROP_CONFERENCE:
      g_value_set_object (value, self->priv->conference);
      break;
    case PROP_SESSION:
      g_value_set_object (value, self->priv->session);
      break;
    case PROP_STREAM:
      g_value_set_object (value, self->priv->stream);
      break;
    case PROP_RTPBIN_PAD:
      g_value_set_object (value, self->priv->rtpbin_pad);
      break;
    case PROP_SSRC:
      g_value_set_uint (value, self->ssrc);
      break;
    case PROP_PT:
      g_value_set_uint (value, self->pt);
      break;
    case PROP_CODEC:
      g_value_set_boxed (value, self->codec);
      break;
    case PROP_RECEIVING:
      g_value_set_boolean (value, self->priv->receiving);
      break;
    case PROP_OUTPUT_GHOSTPAD:
      g_value_set_object (value, self->priv->output_ghostpad);
      break;
    case PROP_NO_RTCP_TIMEOUT:
      g_value_set_int (value, self->no_rtcp_timeout);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
static gpointer
no_rtcp_timeout_func (gpointer user_data)
{
  FsRtpSubStream *self = FS_RTP_SUB_STREAM (user_data);
  GstClock *sysclock = NULL;
  GstClockID id;
  gboolean emit = TRUE;

  sysclock = gst_system_clock_obtain ();
  if (sysclock == NULL)
    goto no_sysclock;

  FS_RTP_SUB_STREAM_LOCK(self);
  id = self->priv->no_rtcp_timeout_id = gst_clock_new_single_shot_id (sysclock,
      self->priv->next_no_rtcp_timeout);

  FS_RTP_SUB_STREAM_UNLOCK(self);
  gst_clock_id_wait (id, NULL);
  FS_RTP_SUB_STREAM_LOCK(self);

  gst_clock_id_unref (id);
  self->priv->no_rtcp_timeout_id = NULL;

  if (self->priv->next_no_rtcp_timeout == 0)
    emit = FALSE;

  FS_RTP_SUB_STREAM_UNLOCK(self);

  gst_object_unref (sysclock);

  if (emit)
    g_signal_emit (self, signals[NO_RTCP_TIMEDOUT], 0);

  return NULL;

 no_sysclock:
  {
    fs_rtp_sub_stream_emit_error (self, FS_ERROR_INTERNAL,
        "Could not get system clock",
        "Could not get system clock");
    return NULL;
  }
}
Beispiel #7
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 void
fs_rtp_sub_stream_constructed (GObject *object)
{
  FsRtpSubStream *self = FS_RTP_SUB_STREAM (object);
  GstPad *valve_sink_pad = NULL;
  GstPadLinkReturn linkret;
  gchar *tmp;

  GST_DEBUG ("New substream in session %u for ssrc %x and pt %u",
      self->priv->session->id, self->ssrc, self->pt);

  if (!self->priv->conference) {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_INVALID_ARGUMENTS, "A Substream needs a conference object");
    return;
  }

  self->priv->rtpbin_unlinked_sig = g_signal_connect_object (
      self->priv->rtpbin_pad, "unlinked", G_CALLBACK (rtpbin_pad_unlinked),
      self, 0);

  tmp = g_strdup_printf ("output_recv_valve_%d_%d_%d", self->priv->session->id,
      self->ssrc, self->pt);
  self->priv->output_valve = gst_element_factory_make ("valve", tmp);
  g_free (tmp);

  if (!self->priv->output_valve) {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not create a valve element for"
      " session substream with ssrc: %u and pt:%d", self->ssrc,
      self->pt);
    return;
  }

  if (!gst_bin_add (GST_BIN (self->priv->conference), self->priv->output_valve))
  {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not add the valve element for session"
      " substream with ssrc: %u and pt:%d to the conference bin",
      self->ssrc, self->pt);
    return;
  }

  /* We set the valve to dropping, the stream will unblock it when its linked */
  g_object_set (self->priv->output_valve, "drop", TRUE, NULL);

  if (gst_element_set_state (self->priv->output_valve, GST_STATE_PLAYING) ==
    GST_STATE_CHANGE_FAILURE) {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not set the valve element for session"
      " substream with ssrc: %u and pt:%d to the playing state",
      self->ssrc, self->pt);
    return;
  }

  tmp = g_strdup_printf ("recv_capsfilter_%d_%d_%d", self->priv->session->id,
      self->ssrc, self->pt);
  self->priv->capsfilter = gst_element_factory_make ("capsfilter", tmp);
  g_free (tmp);

  if (!self->priv->capsfilter) {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not create a capsfilter element for"
      " session substream with ssrc: %u and pt:%d", self->ssrc,
      self->pt);
    return;
  }

  if (!gst_bin_add (GST_BIN (self->priv->conference), self->priv->capsfilter)) {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not add the capsfilter element for session"
      " substream with ssrc: %u and pt:%d to the conference bin",
      self->ssrc, self->pt);
    return;
  }

  if (gst_element_set_state (self->priv->capsfilter, GST_STATE_PLAYING) ==
    GST_STATE_CHANGE_FAILURE) {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not set the capsfilter element for session"
      " substream with ssrc: %u and pt:%d to the playing state",
      self->ssrc, self->pt);
    return;
  }

  tmp = g_strdup_printf ("input_recv_valve_%d_%d_%d", self->priv->session->id,
      self->ssrc, self->pt);
  self->priv->input_valve = gst_element_factory_make ("valve", tmp);
  g_free (tmp);

  if (!self->priv->input_valve) {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not create a valve element for"
      " session substream with ssrc: %u and pt:%d", self->ssrc,
      self->pt);
    return;
  }

  if (!gst_bin_add (GST_BIN (self->priv->conference), self->priv->input_valve))
  {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not add the valve element for session"
      " substream with ssrc: %u and pt:%d to the conference bin",
      self->ssrc, self->pt);
    return;
  }

  if (gst_element_set_state (self->priv->input_valve, GST_STATE_PLAYING) ==
    GST_STATE_CHANGE_FAILURE) {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not set the valve element for session"
      " substream with ssrc: %u and pt:%d to the playing state",
      self->ssrc, self->pt);
    return;
  }

  if (!gst_element_link (self->priv->input_valve, self->priv->capsfilter))
  {
    self->priv->construction_error = g_error_new (FS_ERROR,
        FS_ERROR_CONSTRUCTION, "Could not link the input valve"
        " and the capsfilter");
    return;
  }

  valve_sink_pad = gst_element_get_static_pad (self->priv->input_valve,
      "sink");
  if (!valve_sink_pad)
  {
    self->priv->construction_error = g_error_new (FS_ERROR,
        FS_ERROR_CONSTRUCTION,
        "Could not get the valve's sink pad");
    return;
  }

  linkret = gst_pad_link (self->priv->rtpbin_pad, valve_sink_pad);

  gst_object_unref (valve_sink_pad);

  if (GST_PAD_LINK_FAILED (linkret))
  {
    self->priv->construction_error = g_error_new (FS_ERROR,
        FS_ERROR_CONSTRUCTION,
        "Could not link the rtpbin to the codec bin (%d)", linkret);
    return;
  }

  if (self->no_rtcp_timeout > 0)
    if (!fs_rtp_sub_stream_start_no_rtcp_timeout_thread (self,
            &self->priv->construction_error))
      return;

  GST_CALL_PARENT (G_OBJECT_CLASS, constructed, (object));
}