static void _connection_failed (FsMsnConnection *connection, FsMsnStream *self) { FsMsnConference *conference = fs_msn_stream_get_conference (self, NULL); if (!conference) return; GST_OBJECT_LOCK (conference); self->priv->fd = -1; GST_OBJECT_UNLOCK (conference); gst_element_post_message (GST_ELEMENT (conference), gst_message_new_element (GST_OBJECT (conference), gst_structure_new ("farstream-component-state-changed", "stream", FS_TYPE_STREAM, self, "component", G_TYPE_UINT, 1, "state", FS_TYPE_STREAM_STATE, FS_STREAM_STATE_FAILED, NULL))); fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONNECTION_FAILED, "Could not establish streaming connection"); gst_object_unref (conference); }
static void _state_changed (FsStreamTransmitter *stream_transmitter, guint component, FsStreamState state, gpointer user_data) { FsRtpStream *self = FS_RTP_STREAM (user_data); FsRtpSession *session = fs_rtp_stream_get_session (self, NULL); GstElement *conf = NULL; if (!session) return; g_object_get (session, "conference", &conf, NULL); gst_element_post_message (conf, gst_message_new_element (GST_OBJECT (conf), gst_structure_new ("farstream-component-state-changed", "stream", FS_TYPE_STREAM, self, "component", G_TYPE_UINT, component, "state", FS_TYPE_STREAM_STATE, state, NULL))); gst_object_unref (conf); g_object_unref (session); if (component == 1 && state == FS_STREAM_STATE_FAILED) fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONNECTION_FAILED, "Could not establish connection on the RTP component"); }
static void _substream_src_pad_added (FsRtpSubStream *substream, GstPad *pad, FsCodec *codec, gpointer user_data) { FsStream *stream = FS_STREAM (user_data); fs_stream_emit_src_pad_added (stream, pad, codec); }
static void fs_stream_finalize (GObject *obj) { FsStream *stream = FS_STREAM (obj); g_list_free_full (stream->priv->src_pads, gst_object_unref); g_mutex_clear (&stream->priv->mutex); G_OBJECT_CLASS (fs_stream_parent_class)->finalize (obj); }
static void _substream_error (FsRtpSubStream *substream, gint errorno, gchar *error_msg, gchar *debug_msg, gpointer user_data) { FsStream *stream = FS_STREAM (user_data); fs_stream_emit_error (stream, errorno, error_msg); }
static void _transmitter_error ( FsStreamTransmitter *stream_transmitter, gint errorno, gchar *error_msg, gpointer user_data) { FsStream *stream = FS_STREAM (user_data); fs_stream_emit_error (stream, errorno, error_msg); }
static void fs_stream_constructed (GObject *obj) { FsStream *stream = FS_STREAM (obj); FsSession *session; FsConference *conference; g_object_get (stream, "session", &session, NULL); g_object_get (session, "conference", &conference, NULL); g_signal_connect_object (conference, "pad-removed", G_CALLBACK (fs_stream_pad_removed), obj, G_CONNECT_SWAPPED); g_object_unref (session); g_object_unref (conference); }
static void _rtpbin_pad_blocked_callback (GstPad *pad, gboolean blocked, gpointer user_data) { FsRtpSubStream *substream = user_data; GError *error = NULL; GstElement *codecbin = NULL; FsCodec *codec = NULL; FsRtpSession *session; if (fs_rtp_session_has_disposed_enter (substream->priv->session, NULL)) { gst_pad_set_blocked_async (pad, FALSE, do_nothing_blocked_callback, NULL); return; } if (fs_rtp_sub_stream_has_stopped_enter (substream)) { gst_pad_set_blocked_async (pad, FALSE, do_nothing_blocked_callback, NULL); fs_rtp_session_has_disposed_exit (substream->priv->session); return; } g_object_ref (substream); session = g_object_ref (substream->priv->session); GST_DEBUG ("Substream blocked for codec change (session:%d SSRC:%x pt:%d)", substream->priv->session->id, substream->ssrc, substream->pt); gst_pad_set_blocked_async (pad, FALSE, do_nothing_blocked_callback, NULL); g_signal_emit (substream, signals[GET_CODEC_BIN], 0, substream->priv->stream, substream->codec, &codec, &error, &codecbin); if (error) goto error; if (codecbin) if (!fs_rtp_sub_stream_set_codecbin (substream, codec, codecbin, &error)) goto error; out: g_clear_error (&error); fs_rtp_sub_stream_has_stopped_exit (substream); fs_rtp_session_has_disposed_exit (substream->priv->session); g_object_unref (substream); g_object_unref (session); return; error: { gchar *str = g_strdup_printf ("Could not add the new recv codec bin for" " ssrc %u and payload type %d to the state NULL", substream->ssrc, substream->pt); if (substream->priv->stream) fs_stream_emit_error (FS_STREAM (substream->priv->stream), FS_ERROR_CONSTRUCTION, str, error->message); else fs_session_emit_error (FS_SESSION (substream->priv->session), FS_ERROR_CONSTRUCTION, str, error->message); g_free (str); } goto out; }
static void _connected ( FsMsnConnection *connection, guint fd, gpointer user_data) { FsMsnStream *self = FS_MSN_STREAM (user_data); GError *error = NULL; GstPad *pad; GstElement *fdelem; int checkfd; FsMsnConference *conference = fs_msn_stream_get_conference (self, NULL); GstElement *codecbin = NULL; GstElement *recv_valve = NULL; GstElement *send_valve = NULL; gboolean drop; if (!conference) goto error; GST_DEBUG ("******** CONNECTED %d**********", fd); gst_element_post_message (GST_ELEMENT (conference), gst_message_new_element (GST_OBJECT (conference), gst_structure_new ("farstream-component-state-changed", "stream", FS_TYPE_STREAM, self, "component", G_TYPE_UINT, 1, "state", FS_TYPE_STREAM_STATE, FS_STREAM_STATE_READY, NULL))); if (self->priv->conference->max_direction == FS_DIRECTION_RECV) codecbin = gst_parse_bin_from_description ( "fdsrc name=fdsrc do-timestamp=true ! mimdec ! valve name=recv_valve", TRUE, &error); else codecbin = gst_parse_bin_from_description ( "videoconvert ! videoscale ! mimenc name=enc !" " fdsink name=fdsink sync=false async=false", TRUE, &error); if (!codecbin) { g_prefix_error (&error, "Error creating codecbin: "); fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, error->message); g_clear_error (&error); goto error; } /* So we don't require an unlreased gst-plugins-bad mimenc */ if (self->priv->conference->max_direction == FS_DIRECTION_SEND) { GstElement *mimenc = gst_bin_get_by_name (GST_BIN (codecbin), "enc"); if (g_object_class_find_property ( G_OBJECT_GET_CLASS (mimenc), "paused-mode")) g_object_set (mimenc, "paused-mode", TRUE, NULL); gst_object_unref (mimenc); } if (self->priv->conference->max_direction == FS_DIRECTION_RECV) { fdelem = gst_bin_get_by_name (GST_BIN (codecbin), "fdsrc"); gst_base_src_set_format (GST_BASE_SRC (fdelem), GST_FORMAT_TIME); } else { fdelem = gst_bin_get_by_name (GST_BIN (codecbin), "fdsink"); } if (!fdelem) { fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, "Could not get fd element"); goto error; } g_object_set (fdelem, "fd", fd, NULL); g_object_get (fdelem, "fd", &checkfd, NULL); gst_object_unref (fdelem); if (fd != checkfd) { fs_stream_emit_error (FS_STREAM (self), FS_ERROR_INTERNAL, "Could not set file descriptor"); goto error; } if (self->priv->conference->max_direction == FS_DIRECTION_RECV) pad = gst_element_get_static_pad (codecbin, "src"); else pad = gst_element_get_static_pad (codecbin, "sink"); if (!pad) { fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, "Could not get codecbin pad"); goto error; } if (!gst_bin_add (GST_BIN (conference), codecbin)) { gst_object_unref (pad); fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, "Could not add codecbin to the conference"); goto error; } GST_OBJECT_LOCK (conference); self->priv->fd = fd; self->priv->codecbin = gst_object_ref (codecbin); GST_OBJECT_UNLOCK (conference); if (self->priv->conference->max_direction == FS_DIRECTION_RECV) { FsCodec *mimic_codec; GstPad *src_pad; src_pad = gst_ghost_pad_new ("src_1_1_1", pad); gst_object_unref (pad); GST_OBJECT_LOCK (conference); self->priv->src_pad = gst_object_ref (src_pad); GST_OBJECT_UNLOCK (conference); gst_pad_set_active (src_pad, TRUE); if (!gst_element_add_pad (GST_ELEMENT (conference), src_pad)) { fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, "Could not add src_1_1_1 pad"); gst_object_unref (src_pad); goto error; } recv_valve = gst_bin_get_by_name (GST_BIN (codecbin), "recv_valve"); if (!recv_valve) { fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, "Could not get recv_valve"); gst_object_unref (src_pad); goto error; } GST_OBJECT_LOCK (conference); self->priv->recv_valve = gst_object_ref (recv_valve); drop = !(self->priv->direction & FS_DIRECTION_RECV); GST_OBJECT_UNLOCK (conference); g_object_set (recv_valve, "drop", drop, NULL); mimic_codec = fs_codec_new (0, "mimic", FS_MEDIA_TYPE_VIDEO, 0); fs_stream_emit_src_pad_added (FS_STREAM (self), src_pad, mimic_codec); fs_codec_destroy (mimic_codec); gst_object_unref (src_pad); } else { GstPad *valvepad; GST_OBJECT_LOCK (conference); if (self->priv->session->valve) send_valve = gst_object_ref (self->priv->session->valve); GST_OBJECT_UNLOCK (conference); if (!send_valve) { fs_stream_emit_error (FS_STREAM (self), FS_ERROR_DISPOSED, "Session was disposed"); goto error; } valvepad = gst_element_get_static_pad (send_valve, "src"); if (!valvepad) { gst_object_unref (pad); fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, "Could not get valve sink pad"); goto error; } if (GST_PAD_LINK_FAILED (gst_pad_link (valvepad, pad))) { gst_object_unref (valvepad); gst_object_unref (pad); fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, "Could not link valve to codec bin"); goto error; } gst_object_unref (valvepad); gst_object_unref (pad); } if (!gst_element_sync_state_with_parent (codecbin)) { fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, "Could not start codec bin"); goto error; } if (self->priv->conference->max_direction == FS_DIRECTION_SEND) { GST_OBJECT_LOCK (conference); fs_msn_stream_set_tos_locked (self, self->priv->tos); drop = !(self->priv->direction & FS_DIRECTION_SEND); GST_OBJECT_UNLOCK (conference); g_object_set (send_valve, "drop", drop, NULL); } error: if (send_valve) gst_object_unref (send_valve); if (recv_valve) gst_object_unref (recv_valve); if (codecbin) gst_object_unref (codecbin); if (conference) gst_object_unref (conference); }